<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" version="2.0">
<channel>
<title><![CDATA[Unified Python Planet]]></title>
<description><![CDATA[A uniqued union of the Official and Unofficial Python planet feeds.  Generated by Atomisator FTW!]]></description>
<link>http://feeds2.feedburner.com/UnifiedPythonPlanet</link>
<language>en</language>
<copyright>Copyright 2008, Atomisator</copyright>
<pubDate>Sat, 15 Mar 2008 00:15:05 +0200</pubDate>
<lastBuildDate>Sat, 15 Mar 2008 00:15:05 +0200</lastBuildDate>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/UnifiedPythonPlanet" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="unifiedpythonplanet" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
    <title><![CDATA[Just a little Python: Aggregation in MongoDB (Part 1)]]></title>
    <description><![CDATA[<p>In some previous posts on <a href="http://blog.pythonisito.com/2012/01/getting-started-with-mongodb-and-python.html">mongodb and python</a>, 
<a href="http://blog.pythonisito.com/2012/01/moving-along-with-pymongo.html">pymongo</a>, and <a href="http://blog.pythonisito.com/2012/05/gridfs-mongodb-filesystem.html">gridfs</a>, I introduced the NoSQL database
<a href="http://www.mongodb.org/">MongoDB</a> how to use it from Python, and how to use it to store large
(more than 16 MB) files in it. Here, I'll be showing you a few of the features that the
current (2.0) version of MongoDB includes for performing aggregation. In a future
post, I'll give you a peek into the new aggregation framework included in MongoDB
version 2.1.</p>
<a name="more"></a>

<h2>Basic aggregation</h2>
<p>Included in MongoDB are three operators useful for doing basic multi-document
queries and <a href="http://www.mongodb.org/display/DOCS/Aggregation">aggregations</a>: <code>count()</code>, <code>distinct()</code>, and <code>group()</code>.</p>
<h3>Count</h3>
<p><code>count()</code> is most basic. <code>count()</code> returns the number of
documents that match the cursor's query. To illustrate this, first we'll create
some documents in a <code>test</code> collection:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">random</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">pymongo</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">conn</span> <span class="o">=</span> <span class="n">pymongo</span><span class="o">.</span><span class="n">Connection</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">db</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">agg</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">insert</span><span class="p">([</span>
<span class="gp">... </span>    <span class="nb">dict</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">(),</span> <span class="n">y</span><span class="o">=</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span> 
<span class="gp">... </span>    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">50</span><span class="p">)])</span>
<span class="go">[ObjectId(...)]</span>
</pre></div>


<p>Now, let's count the documents where <code>y</code> is <code>3</code>:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="o">&gt;&gt;&gt;</span> <span class="n">db</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">find</span><span class="p">({</span><span class="s">'y'</span><span class="p">:</span><span class="mi">3</span><span class="p">})</span><span class="o">.</span><span class="n">count</span><span class="p">()</span>
<span class="go">3</span>
</pre></div>


<p>This is normally what we want, but what if our cursor is using a <code>skip()</code> or
<code>limit()</code>? <code>count()</code> ignores those:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">q</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">find</span><span class="p">({</span><span class="s">'y'</span><span class="p">:</span><span class="mi">3</span><span class="p">})</span><span class="o">.</span><span class="n">skip</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">q</span><span class="o">.</span><span class="n">count</span><span class="p">()</span>
<span class="go">3</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">len</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">q</span><span class="p">))</span>
<span class="go">2</span>
</pre></div>


<p>If you want to take skips and limits into account, you'll have to do some (a
trivial amount) of calculation yourself:</p>
<div class="codehilite"><pre><span class="k">def</span> <span class="nf">the_real_count</span><span class="p">(</span><span class="n">count</span><span class="p">,</span> <span class="n">skip</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">limit</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="n">result</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">count</span> <span class="o">-</span> <span class="n">skip</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">limit</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
        <span class="n">result</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">limit</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">result</span>
</pre></div>


<p>Now we can use it:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">the_real_count</span><span class="p">(</span><span class="n">q</span><span class="o">.</span><span class="n">count</span><span class="p">(),</span> <span class="mi">1</span><span class="p">)</span>
<span class="go">2</span>
</pre></div>


<h3>Distinct</h3>
<p>Another thing that's often useful is checking to see which distinct values a
query returns. For this, MongoDB provides the <code>distinct()</code> method:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">find</span><span class="p">({</span><span class="s">'y'</span><span class="p">:</span> <span class="p">{</span><span class="s">'$gt'</span><span class="p">:</span><span class="mi">3</span><span class="p">}})</span><span class="o">.</span><span class="n">distinct</span><span class="p">(</span><span class="s">'y'</span><span class="p">)</span>
<span class="go">[10, 6, 5, 7, 8, 4, 9]</span>
</pre></div>


<p>Note that you need to provide the field you want the distinct values for.</p>
<h3>Group</h3>
<p>With <code>group()</code>, we can perform somewhat more complex calculations. Grouping in
MongoDB is basically equivalent to a <code>reduce()</code> operation in Python; an initial
value is provided, and then all documents in the group are reduced into it using
the <code>reduce</code> function. The actual <code>group()</code> function takes a number of
parameters, most of which must be specified:</p>
<dl>
<dt><code>key</code></dt>
<dd>This can be one of the following:</dd>
</dl>
<ul>
<li><code>None</code>, indicating that the entire document is the group key</li>
<li>A list of property names indicating the group key</li>
<li>A Javascript function which will return the group key when called for each document</li>
</ul>
<dl>
<dt><code>condition</code></dt>
<dd>This is a condition used to filter the <em>input</em> to the group operation (i.e. it
  is equivalent to the <code>WHERE</code> clause in a SQL statement <code>GROUP BY</code>, <em>not</em> the
  <code>HAVING</code> caluse.</dd>
<dt><code>initial</code></dt>
<dd>This is the initial object which will be used to 'kick off' the reduction.</dd>
<dt><code>reduce</code></dt>
<dd>This is a Javascript function which will be used to combine all the matching
documents pairwise until only one remains.</dd>
<dt><code>finalize</code></dt>
<dd>This is an optional Javascript function which will be called on the result of
the reduction to generate the final value. It might useful for computing a mean
value from a sum and count, for instance.</dd>
</dl>
<p>An example is illustrative. To see the count and sum of all the x values in our
collection, grouped by y values, only for y values greater than 3, the query
would be the following:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">key</span> <span class="o">=</span> <span class="p">[</span> <span class="s">'y'</span> <span class="p">]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">condition</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'y'</span><span class="p">:</span> <span class="p">{</span> <span class="s">'$gt'</span><span class="p">:</span> <span class="mi">3</span> <span class="p">}</span> <span class="p">}</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">initial</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'count'</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s">'sum'</span><span class="p">:</span> <span class="mi">0</span> <span class="p">}</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">reduce</span> <span class="o">=</span> <span class="s">'function(doc, out) { out.count++; out.sum += doc.x; }'</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">condition</span><span class="p">,</span> <span class="n">initial</span><span class="p">,</span> <span class="nb">reduce</span><span class="p">)</span>
<span class="go">[{u'y': 10.0, u'count': 6.0, u'sum': 3.9350696527378295}, </span>
<span class="go"> {u'y': 6.0, u'count': 10.0, u'sum': 5.312402119253351}, </span>
<span class="go"> {u'y': 5.0, u'count': 3.0, u'sum': 0.9414083462732217}, </span>
<span class="go"> {u'y': 7.0, u'count': 7.0, u'sum': 2.992867324959482}, </span>
<span class="go"> {u'y': 8.0, u'count': 6.0, u'sum': 1.429589852438617}, </span>
<span class="go"> {u'y': 4.0, u'count': 5.0, u'sum': 1.7804494395579495}, </span>
<span class="go"> {u'y': 9.0, u'count': 3.0, u'sum': 1.6105657361868966}]</span>
</pre></div>


<p>If we would also like to return the mean <code>x</code> value, we can include a <code>finalize</code>
function:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">finalize</span> <span class="o">=</span> <span class="s">'function(out) { out.mean = out.sum / out.count; }'</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">condition</span><span class="p">,</span> <span class="n">initial</span><span class="p">,</span> <span class="nb">reduce</span><span class="p">,</span> <span class="n">finalize</span><span class="p">)</span>
<span class="go">[{u'y': 10.0, u'count': 6.0, u'sum': 3.9350696527378295, u'mean': 0.6558449421229716}, </span>
<span class="go"> {u'y': 6.0, u'count': 10.0, u'sum': 5.312402119253351, u'mean': 0.5312402119253351}, </span>
<span class="go"> {u'y': 5.0, u'count': 3.0, u'sum': 0.9414083462732217, u'mean': 0.3138027820910739}, </span>
<span class="go"> {u'y': 7.0, u'count': 7.0, u'sum': 2.992867324959482, u'mean': 0.42755247499421173}, </span>
<span class="go"> {u'y': 8.0, u'count': 6.0, u'sum': 1.429589852438617, u'mean': 0.23826497540643618}, </span>
<span class="go"> {u'y': 4.0, u'count': 5.0, u'sum': 1.7804494395579495, u'mean': 0.3560898879115899}, </span>
<span class="go"> {u'y': 9.0, u'count': 3.0, u'sum': 1.6105657361868966, u'mean': 0.5368552453956322}]</span>
</pre></div>


<h3>Warning</h3>

<p>You might be thinking that <code>group()</code> is awesome, and it's exactly what you need,
but there are two things to be aware of with <code>group()</code> which may make it a
non-starter for your needs:</p>
<ul>
<li><code>group()</code> cannot be used on sharded collections. It just doesn't work. So if
  you're doing sharding, you'll have to go the <code>mapreduce()</code> route (below).</li>
<li><code>group()</code>, since it uses Javascript, uses the SpiderMonkey global interpreter
  lock, meaning that all Javascript, whether it's a <code>db.eval</code> call, <code>group</code>,
  <code>mapreduce</code>, or <code>$where</code> in a query, must be serialized. So don't plan on doing
  a lot of <code>group()</code>s concurrently.</li>
</ul>
<p>If you're only using <code>group()</code> occasionally on a non-sharded collection, it might
be fine. For a more general and (IMO) better solution, however, read on for <code>mapreduce</code>:</p>
<h2>Map/Reduce</h2>
<p>MongoDB provides an <a href="http://www.mongodb.org/display/DOCS/MapReduce">implementation</a> of the
<a href="http://en.wikipedia.org/wiki/MapReduce">MapReduce</a> algorithm using the collection-level <code>mapreduce</code>
method. Once again, we're using Javascript, so the same caveats apply regarding
the global Javascript interpreter lock, but since <code>mapreduce</code> provides support
for sharding, we can actually squeeze a bit of parallelism out of it here.</p>
<p>One way to think of <code>mapreduce</code> as used in MongoDB is that it is a generalized
<code>group</code> method. The particular differences between <code>mapreudce</code> and <code>group</code> are as
follows:</p>
<ul>
<li><code>mapreduce</code> allows us to provide an initial <code>map</code> function which will be used
  to generate documents to be grouped by key, whereas <code>group</code> only allowed us to
  specify a method that returned the key for a given document.</li>
<li><code>mapreduce</code> allows us to keep our results in a collection in the database,
  rather than returning them immediately the way <code>group</code> does. With <code>mapreduce</code>,
  we also have great flexibility on <em>how</em> those documents are stored in the
  collection. We can do one of the following:</li>
<li>store the results in their own collection, obliterating any existing
    collection of the same name,</li>
<li>store the results in a possibly pre-existing collection, overwriting any
    results that are already there, or</li>
<li>store the results in a possibly pre-existing collection, <em>reducing</em> the
    results with any results currently stored there.</li>
</ul>
<p>So to take up our example from the <code>group</code> discussion above, we can do the same
thing in <code>mapreduce</code> as follows:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">query</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'y'</span><span class="p">:</span> <span class="p">{</span> <span class="s">'$gt'</span><span class="p">:</span> <span class="mi">3</span> <span class="p">}</span> <span class="p">}</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">map</span> <span class="o">=</span> <span class="s">'function() { emit(this.y, { count: 1, sum: this.x}); }'</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">reduce</span> <span class="o">=</span> <span class="s">'''function(key, values) {</span>
<span class="gp">... </span><span class="s">    var result = { count:0, sum: 0 };</span>
<span class="gp">... </span><span class="s">    values.forEach(function(value) {</span>
<span class="gp">... </span><span class="s">        result.count += value.count;</span>
<span class="gp">... </span><span class="s">        result.sum += value.sum; })</span>
<span class="gp">... </span><span class="s">    return result; }'''</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">finalize</span> <span class="o">=</span> <span class="s">'''function(k, v) { </span>
<span class="gp">... </span><span class="s">    return { sum: v.sum, </span>
<span class="gp">... </span><span class="s">             count: v.count,</span>
<span class="gp">... </span><span class="s">             mean: v.sum/v.count } }</span>
<span class="gp">... </span><span class="s">'''</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">map_reduce</span><span class="p">(</span><span class="nb">map</span><span class="p">,</span> <span class="nb">reduce</span><span class="p">,</span> <span class="p">{</span><span class="s">'inline'</span><span class="p">:</span><span class="mi">1</span><span class="p">},</span> <span class="n">query</span><span class="o">=</span><span class="n">query</span><span class="p">,</span> <span class="n">finalize</span><span class="o">=</span><span class="n">finalize</span><span class="p">)</span>
<span class="go">{u'counts': {u'input': 40, </span>
<span class="go">             u'reduce': 7, </span>
<span class="go">             u'emit': 40, </span>
<span class="go">             u'output': 7}, </span>
<span class="go"> u'timeMillis': 4, </span>
<span class="go"> u'ok': 1.0, </span>
<span class="go"> u'results': [</span>
<span class="go">   {u'_id': 4.0, u'value': {</span>
<span class="go">     u'count': 5.0, </span>
<span class="go">     u'sum': 1.7804494395579495, </span>
<span class="go">     u'mean': 0.3560898879115899}}, ...]}</span>
</pre></div>


<p>Note in particular that the structure of our documents has changed. With <code>group</code>, we
were working on 'native' documents from our collection. Now we are working with
"keys" and "values", where the "keys" are whatever was the first argument to
<code>emit</code> in our <code>map</code> fuction, and the "values" are whatever was the second
argument.</p>
<p>The actual <code>mapreduce</code> method takes quite a few parameters in addition
to the required <code>map</code>, <code>reduce</code>, and <code>out</code>:</p>
<dl>
<dt><code>map</code></dt>
<dd><strong>required</strong> The Javascript function that calls <code>emit(key, value)</code> for each input document
  to the <code>reduce</code>. Note that in the <code>map</code> function, <code>this</code> refers to the current
  document being <code>map</code>ped.</dd>
<dt><code>reduce</code></dt>
<dd><strong>required</strong> The Javascript function that takes a key and an array of
 values and which should return the <em>reduction</em> of those values. Note that
 <code>reduce</code> may be called multiple times for a given key, and may be used to
 further reduce an already reduced value, so the value returned from <code>reduce</code>
 should be similar in structure to the values <code>emit</code>ted from <code>map</code>.</dd>
<dt><code>out</code></dt>
<dd><strong>required</strong> (at least in Python) An object specifying what to do with the
  results, whether to return them inline, or to put them into a collection, and
  how to handle putting them into a collection. Options are listed below.</dd>
<dt><code>query</code></dt>
<dd><em>optional</em> A MongoDB query used to filter the collection before sending its
  documents to the <code>map</code> function.</dd>
<dt><code>sort</code></dt>
<dd><em>optional</em> This will cause the input to <code>map</code> to be sorted. Specifying a sort
  key that groups the documents by the key that <code>map</code> will <code>emit()</code> can lead to
  fewer <code>reduce</code> calls. Strictly a performance optimization unless <code>limit</code> is
  used, below.</dd>
<dt><code>limit</code></dt>
<dd><em>optional, not sharding-compatible</em> Limits the number of documents send to <code>map</code>.</dd>
<dt><code>finalize</code></dt>
<dd><em>optional</em> The Javascript function called on the results of <code>reduce</code>. Useful,
  for generating secondary aggregates such as mean.</dd>
<dt><code>scope</code></dt>
<dd><em>optional</em> Used to set the scope variable for <code>map</code>, <code>reduce</code>, and <code>finalize</code></dd>
<dt><code>sharded</code></dt>
<dd>If <code>True</code>, then shard the output collection on its <code>_id</code> field.</dd>
</dl>
<p>There are a few others, but they're less commonly used. The official
<a href="http://en.wikipedia.org/wiki/MapReduce">docs</a> give more details.</p>
<p>The <code>out</code> parameter is one that deserves a bit more explanation. It specifies
what to do with the result of the <code>mapreduce</code> job, and can be of one of the
following formats:</p>
<dl>
<dt><em></em></dt>
<dt><code>{'replace': &lt;collection name&gt;}</code></dt>
<dd>The output is inserted into a collection, atomically replacing any existing
  collection with the same name.</dd>
<dt><code>{'merge': &lt;collection name&gt;}</code></dt>
<dd>The output is inserted into a collection, overwriting any values with the same
  key but not removing the entire collection as <code>replace</code> does.</dd>
<dt><code>{'reduce': &lt;collection name&gt;}</code></dt>
<dd>The contents of the collection are treated as inputs to the <code>reduce</code> step. This
  option allows for incremental updates to an output collection.</dd>
</dl>
<p>You can also specify that the result should be written to another database using
the the <code>out</code> parameter. For this, the order of keys matters and if you're using
Python, you should use a <code>collections.ordereddict</code> or <code>bson.SON</code> object:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">map_reduce</span><span class="p">(</span><span class="nb">map</span><span class="p">,</span> <span class="nb">reduce</span><span class="p">,</span> <span class="n">bson</span><span class="o">.</span><span class="n">SON</span><span class="p">([</span>
<span class="gp">... </span>    <span class="p">(</span><span class="s">'replace'</span><span class="p">,</span> <span class="s">'agg_result'</span><span class="p">),</span> 
<span class="gp">... </span>    <span class="p">(</span><span class="s">'db'</span><span class="p">,</span> <span class="s">'otheragg'</span><span class="p">)</span>
<span class="gp">... </span><span class="p">]),</span> <span class="n">query</span><span class="o">=</span><span class="n">query</span><span class="p">,</span> <span class="n">finalize</span><span class="o">=</span><span class="n">finalize</span><span class="p">)</span>
<span class="go">Collection(Database(Connection('localhost', 27017), u'otheragg'), u'agg_result')</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">conn</span><span class="o">.</span><span class="n">otheragg</span><span class="o">.</span><span class="n">agg_result</span><span class="o">.</span><span class="n">count</span><span class="p">()</span>
<span class="go">7</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">conn</span><span class="o">.</span><span class="n">otheragg</span><span class="o">.</span><span class="n">agg_result</span><span class="o">.</span><span class="n">find_one</span><span class="p">()</span>
<span class="go">{u'_id': 4.0, </span>
<span class="go"> u'value': {</span>
<span class="go">     u'count': 5.0, </span>
<span class="go">     u'sum': 1.7804494395579495, </span>
<span class="go">     u'mean': 0.3560898879115899}}</span>
</pre></div>


<h3>Mapreduce and Sharding</h3>
<p>If you need to get any parallelism out of your <code>mapreduce</code>, you're going to need
to do it on a sharded cluster. If your input collection is sharded, then MongoDB
will send a <code>mapreduce</code> job to each shard to be executed in parallel. Once all
the shards are done, a final reduce/finalize will be run and the output
collection will be written. </p>
<p>The <a href="http://www.mongodb.org/display/DOCS/MapReduce#MapReduce-ShardedEnvironments">details</a> on how this happens in different versions
vary, but the short answer is that if you're using MongoDB versions under
2.1/2.2, you should <em>not</em> shard your output. In 2.2 and above, sharded output of
mapreduce has been overhauled and has much better performance/parallelism.</p>
<p>So what do you think? Anyone using any of the aggregation features in MongoDB?
Interested in doing so? I'd love to hear about it in the comments below.</p><div class="blogger-post-footer"><!-- // MAILCHIMP SUBSCRIBE CODE \\ -->
<a href="http://eepurl.com/ifqEc">Subscribe to our newsletter</a>
<!-- \\ MAILCHIMP SUBSCRIBE CODE // --><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/18508356-7194743562590811430?l=blog.pythonisito.com" alt="" /></div>
<p><a href="http://feedads.g.doubleclick.net/~a/L1vBwnFULGxvKpif2M5EIzfTp84/0/da"><img src="http://feedads.g.doubleclick.net/~a/L1vBwnFULGxvKpif2M5EIzfTp84/0/di" border="0" ismap="true" /></a><br />
<a href="http://feedads.g.doubleclick.net/~a/L1vBwnFULGxvKpif2M5EIzfTp84/1/da"><img src="http://feedads.g.doubleclick.net/~a/L1vBwnFULGxvKpif2M5EIzfTp84/1/di" border="0" ismap="true" /></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=uw-wbCeqnTM:_vffFtrOeTA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=yIl2AUoC8zA" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=uw-wbCeqnTM:_vffFtrOeTA:4cEx4HpKnUU"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=uw-wbCeqnTM:_vffFtrOeTA:4cEx4HpKnUU" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=uw-wbCeqnTM:_vffFtrOeTA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=uw-wbCeqnTM:_vffFtrOeTA:F7zBnMyn0Lo" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=uw-wbCeqnTM:_vffFtrOeTA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=qj6IDK7rITs" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=uw-wbCeqnTM:_vffFtrOeTA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=uw-wbCeqnTM:_vffFtrOeTA:gIN9vFwOqvQ" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=uw-wbCeqnTM:_vffFtrOeTA:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=TzevzKxY174" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=uw-wbCeqnTM:_vffFtrOeTA:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=l6gmwiTKsz0" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=uw-wbCeqnTM:_vffFtrOeTA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=uw-wbCeqnTM:_vffFtrOeTA:V_sGLiPBpWU" border="0" /></a>
</div><img src="http://feeds.feedburner.com/~r/JustALittlePython/~4/uw-wbCeqnTM" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/JustALittlePython/~3/uw-wbCeqnTM/aggregation-in-mongodb-part-1.html]]></link>
    <pubDate>2012-05-30 14:32:41</pubDate>
  </item>
  <item>
    <title><![CDATA[Frank Wierzbicki: Jython 2.7 alpha1 released!]]></title>
    <description><![CDATA[On behalf of the Jython development team, I'm pleased to announce that Jython 2.7 alpha1 is available for <a href="http://sourceforge.net/projects/jython/files/jython-dev/2.7.0a1/jython_installer-2.7a1.jar/download">download</a>. See the <a href="http://wiki.python.org/jython/InstallationInstructions">installation instructions</a>.<br /><br /> I'd like to thank <a href="http://adconion.com/">Adconion Media Group</a> for sponsoring my work on Jython 2.7. I'd also like to thank the many contributors to Jython.  Jython 2.7 alpha1 implements much of the functionality introduced by CPython 2.6 and 2.7. There are still some missing features, in particular bytearray and the io system are currently incomplete. <br /> Please <a href="http://bugs.jython.org/">report any bugs</a> that you find. Thanks!<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/14276139-3553685527781671501?l=fwierzbicki.blogspot.com" alt="" /></div>]]></description>
    <link><![CDATA[http://fwierzbicki.blogspot.com/2012/05/jython-27-alpha1-released.html]]></link>
    <pubDate>2012-05-30 13:11:12</pubDate>
  </item>
  <item>
    <title><![CDATA[Frank Wierzbicki: Jython 2.7 alpha2 released!]]></title>
    <description><![CDATA[On behalf of the Jython development team, I'm pleased to announce that Jython 2.7 alpha2 is available for <a href="http://sourceforge.net/projects/jython/files/jython-dev/2.7.0a2/jython_installer-2.7a2.jar/download">download</a>. See the <a href="http://wiki.python.org/jython/InstallationInstructions">installation instructions</a>.<br /><br /> I'd like to thank <a href="http://adconion.com/">Adconion Media Group</a> for sponsoring my work on Jython 2.7. I'd also like to thank the many contributors to Jython.  Jython 2.7 alpha2 fixes a serious bug where site-packages failed to appear in the path. There are still some missing features, in particular bytearray and the io system are currently incomplete. <br /> Please <a href="http://bugs.jython.org/">report any bugs</a> that you find. Thanks!<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/14276139-1217879481810360698?l=fwierzbicki.blogspot.com" alt="" /></div>]]></description>
    <link><![CDATA[http://fwierzbicki.blogspot.com/2012/05/on-behalf-of-jython-development-team-im.html]]></link>
    <pubDate>2012-05-30 13:09:43</pubDate>
  </item>
  <item>
    <title><![CDATA[Just a little Python: Review: Web2Py Application Development Cookbook]]></title>
    <description><![CDATA[<img src="http://www.assoc-amazon.com/e/ir?t=pythonisitobl-20&l=as2&o=1&a=1849515468" width="1" height="1" border="0" alt="" />


<p>Changing things up a bit, today I have a special treat, as Jay Kelkar, an avid Pythonista and fellow member of the Python Atlanta user group, has agreed to write a guest post reviewing the 
<a href="http://www.amazon.com/gp/product/1849515468/ref=as_li_ss_tl?ie=UTF8&tag=pythonisitobl-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=1849515468">web2py Application Development Cookbook</a>. If you give him half a chance, Jay will be happy to expound upon the benefits of Web2Py, so this review seemed a perfect fit for him. So without further introduction, here's Jay's review of 
<a href="http://www.amazon.com/gp/product/1849515468/ref=as_li_ss_tl?ie=UTF8&tag=pythonisitobl-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=1849515468">web2py Application Development Cookbook</a>. </p>
<a name="more"></a>
<div class="section" id="review-web2py-application-development-cookbook">

<a href="http://www.amazon.com/gp/product/1849515468/ref=as_li_ss_il?ie=UTF8&tag=pythonisitobl-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=1849515468"><img border="0" src="http://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&Format=_SL110_&ASIN=1849515468&MarketPlace=US&ID=AsinImage&WS=1&tag=pythonisitobl-20&ServiceVersion=20070822" /></a>
<p>For years I have been focused in making things easier for users while putting attention on important matters . I have been interested in all things Python for over 10 years. There are many Python frameworks available and most are libraries with suggestions on how to use them to create web applications. Then web2py came to my notice, a Python web framework which does things quite differently from other popular web frameworks. The two features that put it above the others are: the developer deals more with the problem at hand and rather than the framework, and the built in ability to allow switching between major databases with very little effort. I have been using web2py for over 3 years and have written several major applications with web2py. I wondered if I would find in the book anything that would make me sit up and take notice. So it is with this in mind that I review 
<a href="http://www.amazon.com/gp/product/1849515468/ref=as_li_ss_tl?ie=UTF8&tag=pythonisitobl-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=1849515468">web2py Application Development Cookbook</a>
by Mariano Reingart, Bruno Cezar Rocha, Jonathan Lundell, Pablo Martín Mulone, Michele Comitini, Richard Gordon, and Massimo Di Pierro (the lead developer for web2py).</p>
<p>Web2py is unique in many respects and what is positive to one programmer may appear negative to another. Some of the distinguishing characteristics follow. It is based on the MVC principle - which states that the Model which describes the data and its access, the View which displays or renders the data, and the Controller which manipulates the data, are kept separate and distinct. Unless you want to do something out of the ordinary, no modules need to be imported. It's ORM is distinctly SQLish, so anyone familiar with SQL will feel completely at home. Another is that it will automatically update the database schema to the model on request - this can be desirable in development. It can host multiple apps under one server. In addition, it requires no installation and is ready to run after it is unzipped into the target directory.</p>
</div>
<div class="section" id="summary">
<h2>Summary</h2>
<p>This is a good book. It is aimed at users who are somewhat familiar with web2py and Python. It has a good breadth in popular areas of interest and in most cases gives a good in-depth treatment to each with explanations of how things actually work. It assumes that you are familiar with web2py and Python. Some knowledge of JavaScript, HTML and CSS will also be helpful but not absolutely necessary. If you want to learn web2py I would instead point you to <a class="reference external" href="http://web2.py.com/book">http://web2.py.com/book</a>, which is the preferred source for web2py documentation online. This book does not pretend to teach Python, JavaScript, HTML or CSS. If you are new to Python, this is definitely not the book for you.</p>
</div>
<div class="section" id="synopsis">
<h2>Synopsis</h2>
<p>This book is partitioned into chapters each of which has a central theme and in each chapter they present a list of items covered. This book, while being a great learning resource, will be a very handy reference in cases that are not common to most apps but are important when needed. Examples like PayPal integration, auth using FaceBook, and archiving database updates instantly come to mind. The web2py framework is under active development and since the documentation lags the software, it is impossible to know all the latest <em>goodies</em> in web2py unless you live on the developer newsgroup. I was pleasantly surprised at the new nuggets of functionality I found.</p>
<p>The book opens with a detailed treatment of issues related to getting web2py ready for production use. The depth gives us an idea of the level of detail we can expect from the rest of the book. It shows how it is possible to run web2py behind virtually every major popular web server and how to make it secure.</p>
<p>Even though some familiarity with web2py is assumed, it proceeds to give a thorough account of how to build applications on web2py in <em>Chapter 2</em>. Instead of the usual applications like to-do list or a simple comment system, it shows applications that are useful even after their value for learning is over.</p>
<p>In <em>Chapter 3</em>,  the Database Abstraction Layer is explained at length. Many examples are given to illustrate its power and to show how it meets programmer's needs. This chapter also covers generating a model from an existing MySQL and PostgreSQL database, which helps if web2py is being used to create an app based on an existing database. This effectively shows the power of DAL while showing how to leverage it to do most commonly required tasks.</p>
<p>In <em>Chapter 4</em>,  the focus is on an advanced version of forms. Forms can be easily generated using web2py, however this chapter deals with needs that are often just beyond normal forms or for items in a form that do not necessarily relate to data. Examples include adding Cancel buttons to a form, forms for uploading files and creating forms with fields originating from more than one table.</p>
<p><em>Chapter 5</em> deals with using Ajax to enhance widgets. It also talks about ways to use fancy widgets to display tabular data with full Ajax support.</p>
<p>In <em>Chapter 6</em>, the book shows how to integrate third party libraries with web2py, showing among other uses how to customize logging, working with tweets and using matplotlib.</p>
<p><em>Chapter 7</em> brings us ideas on working with services with web2py. In examples shown you can see how easy it is to consume a variety of services. Like JSON from web2py using jQuery, making RPC calls from Flex, integrating PayPal service, or creating SOAP web services.</p>
<p><em>Chapter 8</em> deals with authentication and authorization, it explains how to use the auth system in web2py and gives several ways to implement authorization in the apps. Authenticating with Facebook is a very useful recipe because Facebook is so popular.</p>
<p><em>Chapter 9 and 10</em> bring you ideas on routing and reporting. It is possible to route within web2py or outside it using a web server. Examples are given with detailed explanations of how this is done for various situations. The chapter on reporting mainly deals with converting the displayed page to pdf and other related ideas.</p>
<p><em>Chapter 11</em>, the final chapter,  is a repository for all recipes which did not fit into any of the above topics. I particularly liked knowing how to debug a running app on the web using the embedded web2py debugger. They also show miscellaneous tips and tricks which come in handy.</p>
<h2>Conclusion</h2>
<p>Having contributed to the web2py framework itself, the authors have a vast amount of experience and the book shares what they know in a very useable format. Code is explained in some detail where necessary and the code was included with the book I reviewed. There are a few errors in the text and small examples shown. The book shows how to use web2py to solve most common and many not so common needs while writing web apps. The book is interesting to read and easy to follow. I did find some code discussed to take up too much space, almost distracting from the flow. However, had I been interested in that recipe, I am sure I would have welcomed the detailed treatment given to the topic. This book will prove a good addition to a web2py user's library.</p>
<h2>About the Author</h2>
<p><em>Jay Kelkar</em> has 30 years experience in programming and web development. He has a Master's degree in Computer Science from University of SouthWestern Louisiana at Lafayette and a Bachelor's degree in Pure Math from Southern Illinois University at Carbondale. His professional interest is in solving problems. His experience includes programming Class 5 telecom switches, programming at all levels on many UNIX platforms (OS, apps, X11 and scripting), and on MS Windows he sticks to programming in portable languages: mostly Python and Ruby. He was an SAP Basis Consultant for 15 years where he connected SAP with many other systems and solving problems that go with running a large system. His area of expertise includes all kinds of software tools, large databases, data interchange and making it easy for users to get work done.</p>
</div><div class="blogger-post-footer"><!-- // MAILCHIMP SUBSCRIBE CODE \\ -->
<a href="http://eepurl.com/ifqEc">Subscribe to our newsletter</a>
<!-- \\ MAILCHIMP SUBSCRIBE CODE // --><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/18508356-3489632302298775831?l=blog.pythonisito.com" alt="" /></div>
<p><a href="http://feedads.g.doubleclick.net/~a/T_zc39m1Y7B6FC3JQSmvXuOJJVQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/T_zc39m1Y7B6FC3JQSmvXuOJJVQ/0/di" border="0" ismap="true" /></a><br />
<a href="http://feedads.g.doubleclick.net/~a/T_zc39m1Y7B6FC3JQSmvXuOJJVQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/T_zc39m1Y7B6FC3JQSmvXuOJJVQ/1/di" border="0" ismap="true" /></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=izp89GEuq1E:2IeuwlMVxJ8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=yIl2AUoC8zA" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=izp89GEuq1E:2IeuwlMVxJ8:4cEx4HpKnUU"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=izp89GEuq1E:2IeuwlMVxJ8:4cEx4HpKnUU" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=izp89GEuq1E:2IeuwlMVxJ8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=izp89GEuq1E:2IeuwlMVxJ8:F7zBnMyn0Lo" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=izp89GEuq1E:2IeuwlMVxJ8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=qj6IDK7rITs" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=izp89GEuq1E:2IeuwlMVxJ8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=izp89GEuq1E:2IeuwlMVxJ8:gIN9vFwOqvQ" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=izp89GEuq1E:2IeuwlMVxJ8:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=TzevzKxY174" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=izp89GEuq1E:2IeuwlMVxJ8:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=l6gmwiTKsz0" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=izp89GEuq1E:2IeuwlMVxJ8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=izp89GEuq1E:2IeuwlMVxJ8:V_sGLiPBpWU" border="0" /></a>
</div><img src="http://feeds.feedburner.com/~r/JustALittlePython/~4/izp89GEuq1E" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/JustALittlePython/~3/izp89GEuq1E/review-web2py-application-development.html]]></link>
    <pubDate>2012-05-30 11:26:12</pubDate>
  </item>
  <item>
    <title><![CDATA[Nick Coghlan: Django's CBVs are not a mistake (but deprecating FBVs might be)]]></title>
    <description><![CDATA[This <a href="http://lukeplant.me.uk/blog/posts/djangos-cbvs-were-a-mistake">interesting piece</a> from Luke Plant went by on Planet Python this morning, and really helped me in understanding many of the complaints I see about Django's Class Based Views. That problem seems to be that when CBVs were introduced, they were brought in as a <i>replacement for</i> the earlier procedural Function Based Views, rather than as a lower level <i>supplemental</i> API that covered an additional set of use cases that weren't being adequately served by the previous approach (I only started using Django with 1.3, so it's taken me a while to come up to speed on this aspect of the framework's history).<br /><br />The key point in Luke's article that I agree with is that deprecating FBVs <i>in favour of</i> CBVs and saying the latter is always the superior solution is a mistake. The part I <i>disagree</i> with is that saying this also means that introducing the CBV concept itself was a mistake. CBVs may have been oversold as the "one true way" to do Django views, but "There's one - and preferably only one - obvious way to do it" is <i>not</i> meant to apply at the level of programming paradigms. Yes, it's a design principle that's part of the Zen of Python, and it's a good philosophy to help reduce needless API complication, but when it comes to the complexities of real world programming, you need flexibility in your modelling tools, or you end up fighting the limitations of your tools instead of being able to clearly express your intent.<br /><br />Procedural programming, functional programming, object-oriented programming, pipeline-based programming etc - they're all different ways to approach a problem space, and Python is deliberately designed to support all of them.<br /><br />It helps to know a bit of programming history and the origins of OOP in the context of this discussion, as Django's FBVs are very similar to implementations of OOP in C and other languages with no native OOP support: you have an object (the HTTP request) and a whole lot of functions that accept that object as their first argument.<br /><br />Thus, when you don't use CBVs at all, what you're really doing is bypassing Python's native OO support in favour of a truckload of what are effectively methods on request objects (just written in a procedural style). If you want to pass state around you either store it on the request, you store it in global state (which includes your cache and main datastore) or you pass it explicitly as function arguments (which means you have to daisy chain it to anyone else that needs it). If you use classes instead, then you get an additional mechanism that you can use to affect behaviour for a subset of your views. For example, I recently restricted write access to the PulpDist REST API to site admins, when it had previously been open to all logged in users. I could do that in one place and be confident it affected the entire API because every REST view in PulpDist inherits from a common base class. Since that base class now enforces the new access restrictions, the entire API obeys the rules even though I only changed one class.<br /><br />Where Luke is absolutely right, though, is that switching from a procedural approach to an object-oriented one comes with a cost, mostly in the form of non-local effects and non-obvious flow control. If you look at Python's standard library, a rather common model to alleviate this problem is the idea of providing an implementation class, which you can choose to use directly, <i>as well as</i> a set of module level convenience functions. Much of the time, using the convenience functions is a better choice, since they're designed to be simple and clean solutions to common tasks. However, if you need to start tweaking, then being able to either instantiate or subclass the existing backend implementation directly lets you get a lot further before you have to resort to the brute force copy-paste-edit approach to code reuse.<br /><br />But please, don't confuse "Django's Generic View implementation is overly complicated and FBVs should be retained as an officially blessed and supported convenience API" with "CBVs are a bad idea". Making the latter claim is really saying "OOP is a bad idea", which is not a supportable assertion (unless you want to argue with decades of CS and software engineering experience). While the weaker claim that "An OOP implementation is often best presented to the API user behind a procedural facade" is less exciting, it has the virtue of being more universally true. Procedural APIs often <i>are</i> simpler and generally introduce less coupling between components. The trick with exposing an OOP layer as well is that it increases the options for your users, as they can now:<br /><br /><ul><li>Just use the procedural layer (Huzzah! Low coupling is good)</li><li>Use the OOP layer through composition (OK, better than reinventing the wheel and coupling is still fairly low when using composition)</li><li>Use the OOP layer through inheritance (Eek, coupling is increasing substantially now, but it's typically still better than copy-paste-edit style reuse)</li><li>Use the upstream implementation as a reference or starting point when writing your own (coupling drops back to zero, but the line count of code that is directly part of the current project just went up substantially)</li></ul>Where Django has arguably made a mistake is in thinking that exposing an OOP layer directly is a reasonable substitute for a pre-existing procedural layer. In general, that's not going to be the case for all the reasons Luke cites in his article. Having the procedural layer become a thin veneer around the published object oriented layer would probably be a good thing, while deprecating it and actively discouraging it's use, even for the cases it handles cleanly, seems potentially unwise.<br /><br />A good example of this layered approach to API design is the <span>str.format</span> method. The main API for that is of course the <span>str.format()</span> method itself and that covers the vast majority of use cases. If you just want to customise the display of a particular custom type, then you can provide a <span>__format</span>__ method directly on that class. However, if you want to write a completely custom formatter (for example, one that automatically quotes interpolated values with <span>shlex.quote</span>), then the <span>string.Formatter</span> class is exposed so that you can take advantage of most of the builtin formatting machinery instead of having to rewrite it yourself. Contrast that with the older %-based approach to formatting - if you want to implement a custom formatter based on that, you're completely on your own, the standard library provides no help whatsoever. PEP 3101 provides some of the rationale behind the layered string formatting API. It's by no means perfect, but perfection wasn't the goal - the goal was providing something more flexible and less quirky than %-style formatting, and in that it succeeded admirably. The key lesson that's applicable to Django is that <span>string.Formatter</span> isn't a replacement for <span>str.format</span>, it's a supplement for the relatively rare cases where the simple method API isn't flexible enough.<br /><br />A few other examples of this layered API design that spring immediately to mind are the logging module (which provides convenience functions to pass messages directly to the root logger), subprocess (with a few convenience functions that aim to largely hide the Swiss army knife that is <span>subprocess.Popen</span>), textwrap (with <span>textwrap.dedent()</span> providing a shorthand for a particular way of using <span>textwrap.TextWrapper</span>), pickle, json, importlib... You get the idea :)<br /><br />Update: Toned down the title and the paragraph after the bulleted list slightly. Since I've never used them myself, I don't know enough about the abuses of FBVs to second guess the Django core devs motivations for actively encouraging the switch to CBVs.<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/9320223-9051661330574510035?l=www.boredomandlaziness.org" alt="" /></div>]]></description>
    <link><![CDATA[http://www.boredomandlaziness.org/2012/05/djangos-cbvs-are-not-mistake-but.html]]></link>
    <pubDate>2012-05-29 23:39:44</pubDate>
  </item>
  <item>
    <title><![CDATA[Python 4 Kids: Being Exceptional]]></title>
    <description><![CDATA[<p><a href="http://www.ibras.dk/montypython/episode41.htm#1">Lady     Yes this looks the sort of thing. May I just try it?</a><br />
<a href="http://www.ibras.dk/montypython/episode41.htm#1">Assistant     Certainly, madam.</a><br />
<a href="http://www.ibras.dk/montypython/episode41.htm#1">    The lady presses button and a sheet of flame shoots out across the hall.</a><br />
<a href="http://www.ibras.dk/montypython/episode41.htm#1">Lady     Oh! Sorry! So sorry! (she is happy though) Yes that&#8217;s fine.</a><br />
<a href="http://www.ibras.dk/montypython/episode41.htm#1">Assistant     Is that on account, madam?</a><br />
<a href="http://www.ibras.dk/montypython/episode41.htm#1">Lady     Yes. </a></p>
<p>Apparently, in Python, it is easier to ask for forgiveness rather than seek permission.   That is to say, the normal approach when writing Python code is to assume that what you are trying to do will work properly.  If something exceptional happens and the code doesn&#8217;t work the way you were hoping, then the Python interpreter will tell you of the error so that you can handle that exceptional circumstance.  This general approach, of trying to do something, then cleaning up if something goes wrong is <a href="http://en.wiktionary.org/wiki/acronymically">acronymically</a> called EAFP (&#8220;easier to ask for forgiveness than permission.  Here is a (somewhat silly) example:</p>
<p><pre class="brush: python;">
&gt;&gt;&gt; a= 1
&gt;&gt;&gt; b=&quot;2&quot;
&gt;&gt;&gt; a+b
Traceback (most recent call last):
File &quot;&quot;, line 1, in
TypeError: unsupported operand type(s) for +: 'int' and 'str'
</pre></p>
<p>What has happened is that we have tried to add a word (ie the <em>string</em> &#8220;2&#8243;) to a number (the <em>integer</em> 1).  Addition doesn&#8217;t make any sense in this circumstance, so Python &#8220;throws&#8221; an &#8220;exception&#8221;.  In this case the exception is called a TypeError.   The problem with this is that when an exception is raised, then unless the program deals with the exception, the Python interpreter will step in, stop the program and print an error message like the one above.</p>
<p>Python deals with this by the <a href="http://docs.python.org/tutorial/errors.html">try/except structure</a>. You try to do the statements in the first block of code, and if there is an exception (that is, you failed when you tried), then you do the statements in the second block of code.</p>
<p><pre class="brush: python;">
&gt;&gt;&gt; try:
...    print a+b      # this is the first block of code and can be multiple statements
... except TypeError:
...    print &quot;Can't add those things together!&quot; # this is the second block of code
...
Can't add those things together!
</pre></p>
<p>Can you see that no exception was raised here?  As far as the Python interpreter is concerned, everything ran smoothly.  The program tried to print a+b, and, in doing so, tried to work out what a +b is.  However, it failed because a is a number and b is a string.  Because it failed nothing got printed in the first block of code.  Also because the specific failure was a TypeError, the second block of code was run.</p>
<p>A short code snippet can show you how this works:</p>
<p><pre class="brush: python;">
&gt;&gt;&gt; c = [1,&quot;2&quot;,2,3,4,5]
&gt;&gt;&gt; sumOfc = 0
&gt;&gt;&gt; # Try Number 1 - this will fail
&gt;&gt;&gt; for number in c:
...     sumOfc += number
...
Traceback (most recent call last):
File &quot;&lt;stdin&gt;&quot;, line 2, in &lt;module&gt;
TypeError: unsupported operand type(s) for +=: 'int' and 'str'
&gt;&gt;&gt; # Try Number 2 - this will work
&gt;&gt;&gt; sumOfc = 0  # need to reset the sum
&gt;&gt;&gt; for number in c:
...     try:
...        sumOfc += number
...     except TypeError:
...        pass
...
&gt;&gt;&gt; sumOfc
15
</pre></p>
<p>In the first try, the interpreter ran into the string &#8220;2&#8243; and didn&#8217;t know what to do, so gave up.  In the second try, the interpreter knew exactly what to do if there was a problem with the addition (<em>pass</em> &#8211; or, in other words &#8220;do nothing&#8221;[see note 1]) so it went through the whole of the array adding up the things that were numbers without complaining.</p>
<p>Of course, you don&#8217;t use try/except blocks around everything.  You will usually have an idea about the parts of the code where something goes wrong.  You can put that code in a try/except block, with code to deal with a failure.  What you shouldn&#8217;t ever do is this:</p>
<p><pre class="brush: python;">
&gt;&gt;&gt; sumOfc = 0
&gt;&gt;&gt; c = [1,&quot;2&quot;,2,3,4,5]
&gt;&gt;&gt; for number in c:
...     try:
...        sumOfc += number
...     except:   # &lt;- Don't do this!
...        pass
...
&gt;&gt;&gt; sumOfc
15
</pre></p>
<p>It is not entirely obvious what is wrong here &#8211; the code works just as well as before.  The only difference is in the except line &#8211; there is no exception specified.   The reason that this is bad isn&#8217;t that the code doesn&#8217;t work well, but, rather, that it works too well.  Every exception will be caught here, not just the one that you were expecting.  This is bad because if some other problem arises in your try block, you&#8217;ll never learn about it and your exception code will probably deal with it incorrectly.  You won&#8217;t know why your program doesn&#8217;t work because the interpreter won&#8217;t tell you.</p>
<p>The other approach to dealing with possible errors is called Look Before You Leap (LBYL).  LBYL involves making sure everything is right before you actually do the thing you do the problematic operation.  So, for example, you might check that what you were trying to add was an integer:</p>
<p><pre class="brush: python;">
&gt;&gt;&gt; c = [1,&quot;2&quot;,2,3,4,5]
&gt;&gt;&gt; sumOfc = 0
&gt;&gt;&gt; for number in c:
...    if isinstance(number,int):
...       sumOfc += number
...
&gt;&gt;&gt; sumOfc
15
</pre></p>
<p>Here the <em>isinstance()</em> <em>function</em> is another feature of Python introspection.  It tests whether the <em>variable</em> <em>number</em> is an <em>integer</em> (&#8220;int&#8221;).  So this code doesn&#8217;t even bother trying to add the number unless its an integer.  It first checks &#8220;is this an integer I see before me?&#8221;  If so, it adds it, if not, it ignores it.   Which is fine as far as it goes&#8230;</p>
<p>The problem with this is that it&#8217;s the wrong way around.  You&#8217;re not really interested in whether or not the thing you&#8217;re adding is an integer.  Rather, you&#8217;re interested in knowing whether <em>addition</em> is meaningful [see note 2].  In fact, this way of approaching things is broken:</p>
<p><pre class="brush: python;">
&gt;&gt;&gt; c = [1,&quot;2&quot;,2,3,4,5.2]
&gt;&gt;&gt; sumOfc = 0
&gt;&gt;&gt; for number in c:
...    if isinstance(number,int):
...       sumOfc += number
...
&gt;&gt;&gt; sumOfc
10
</pre></p>
<p>We&#8217;ve changed the last number in the array to be 5.2, but this causes it to be ignored because it isn&#8217;t an integer &#8211; ooops!  Applying the earlier try/except code gives the right result though:</p>
<p><pre class="brush: python;">&gt;&gt;&gt; c = [1,&quot;2&quot;,2,3,4,5.2]
&gt;&gt;&gt; sumOfc = 0
&gt;&gt;&gt; for number in c:
...     try:
...         sumOfc += number
...     except TypeError:
...         pass
...
&gt;&gt;&gt; sumOfc
15.199999999999999
</pre></p>
<p>Well, accurate up to the rounding error&#8230;  Our try/except code gave us floating point addition for &#8220;free&#8221;, where the LBYL failed.  In fact, it&#8217;s even more interesting because how it works is dependent on what we define sumOfc to be:</p>
<p><pre class="brush: python;">&gt;&gt;&gt; sumOfc = ''
&gt;&gt;&gt; for number in c:
...     try:
...         sumOfc += number
...     except TypeError:
...         pass
...
&gt;&gt;&gt; sumOfc
'2'
</pre></p>
<p>Wow! If that didn&#8217;t make you giddy with excitement, I don&#8217;t know what will.  The same code works if we make <em>sumOfc</em> a string.  Implicitly then we&#8217;re asking Python  to join the strings (which is what + means for a string) together and ignore stuff that can&#8217;t be joined.   We got this entirely for free from our try/except structure, something that would have needed reworking in the LBYL.  In fact, we could use this structure for any object that has addition defined for it.  It&#8217;s this sort of clever which makes Python so good.</p>
<p><strong>Caveat:</strong></p>
<p>Normally the place to use exceptions is where, every once in a while, something out of the ordinary will happen and you have some idea about how it will be out of the ordinary.  In the first case, if it&#8217;s not unusual then it&#8217;s not exceptional &#8211; don&#8217;t handle it with exceptions.  In the second case, if you can&#8217;t identify how it will be out of the ordinary you can&#8217;t deal with it in your except block.</p>
<p><strong>Notes:</strong></p>
<p>1. The point of the except block is to deal with any problems in the try block.  In this case you might try to convert the value to an integer in order that it could be added.</p>
<p>2. Implicitly we&#8217;re talking here about breaking interfaces. You, as a programmer, shouldn&#8217;t be concerned with what is going on under the hood.  You should be able to rely on the fact that an addition method is defined for an object.  If it is, then  you ought to be able to use it without having to know the internal details of the object.  So in the example here, addition is meaningful between integers and floating point numbers, but addition is also meaningful between two strings.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/python4kids.wordpress.com/495/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/python4kids.wordpress.com/495/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/python4kids.wordpress.com/495/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/python4kids.wordpress.com/495/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/python4kids.wordpress.com/495/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/python4kids.wordpress.com/495/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/python4kids.wordpress.com/495/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/python4kids.wordpress.com/495/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/python4kids.wordpress.com/495/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/python4kids.wordpress.com/495/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/python4kids.wordpress.com/495/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/python4kids.wordpress.com/495/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/python4kids.wordpress.com/495/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/python4kids.wordpress.com/495/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=python4kids.wordpress.com&blog=14472219&post=495&subd=python4kids&ref=&feed=1" width="1" height="1" />]]></description>
    <link><![CDATA[http://python4kids.wordpress.com/2012/05/29/being-exceptional/]]></link>
    <pubDate>2012-05-29 22:26:37</pubDate>
  </item>
  <item>
    <title><![CDATA[Michael Schurter: Building Python 2.6.8 on Ubuntu 12.04]]></title>
    <description><![CDATA[<p>Ubuntu 12.04 builds OpenSSL without SSLv2. Python 2.6.8 expects OpenSSL to be built with SSLv2.</p>
<p><a href="http://bugs.python.org/issue12012">This is a bug that has been fixed in Python 2.7+</a>, but it wasn&#8217;t backported for Python 2.6.</p>
<p>So if you build your own Python 2.6 binaries on Ubuntu 12.04 you&#8217;ll see errors like this when attempting to use anything SSL related:</p>
<p><code>*** WARNING: renaming "_ssl" since importing it failed: build/lib.linux-x86_64-2.6/_ssl.so: undefined symbol: SSLv2_method</code></p>
<p>Some of us still need Python 2.6, so <a href="https://bitbucket.org/schmichael/cpython-v2.6.8-nosslv2/src/d77684a8fdd5">I forked Python 2.6.8 and removed SSLv2 support</a>. Tests pass and SSL works.</p>
<p>You can also just grab the diff below:</p>
<p></p>
<p><strong>Update:</strong> M2Crypto requires patching as well: </p>]]></description>
    <link><![CDATA[http://blog.schmichael.com/2012/05/29/building-python-2-6-8-on-ubuntu-12-04/]]></link>
    <pubDate>2012-05-29 22:17:15</pubDate>
  </item>
  <item>
    <title><![CDATA[Mozilla Web Development: Mozilla Webdev’s Beer and Tell: May 18, 2012]]></title>
    <description><![CDATA[<p>Another month, <a href="https://wiki.mozilla.org/Webdev/Beer_And_Tell/May2012">another Beer and Tell</a>: <a href="http://blog.mozilla.org/webdev/2012/04/04/mozilla-webdev-beer-and-tell-march-16-2012/">Remember</a>, a <em>Beer and Tell</em> is a monthly Mozilla Webdev event featuring a series of lightning talks while staying hydrated with a beverage of choice.</p>
<p>We successfully recorded this installment! If you just want to watch it, scroll all the way down. Otherwise, read on for a short description of the projects shown off this time.</p>
<h3>MDN Dev Derby: WebSockets</h3>
<p>groovecoder plugs this month&#8217;s <a href="https://developer.mozilla.org/en-US/demos/devderby">MDN Dev Derby</a>. Dev Derby is a monthly web developer challenge on the Mozilla Developer Network. This time, it focuses on <strong>WebSockets</strong> and groovecoder gives some helpful hints on how to implement secure websockets using an HTTPS-capable <a href="http://nodejitsu.com/">nodejitsu</a> instance.</p>
<p><img src="http://blog.mozilla.org/webdev/files/2012/05/devderby.jpg" alt="" title="MDN Dev Derby" width="550" height="334" class="aligncenter size-full wp-image-2733" /></p>
<h3>Test Manifest dot com</h3>
<p>gkoberger&#8217;s latest project <a href="http://testmanifest.com"><strong>testmanifest.com</strong></a> generates random <a href="https://developer.mozilla.org/en/Apps/Manifest">open web app manifests</a> for testing. Why would you need that? If you&#8217;re developing against tools that handle various different open web apps, then both Firefox and the Marketplace app will require these files be distinct. So potentially, you&#8217;d be spending a lot of time generating new, fake, web app manifests. <em>Test Manifest</em> helps you do exactly that: Edit and host a bunch of manifests to use for developing open web apps-related tools, without manually generating new ones all the time.</p>
<p><img src="http://blog.mozilla.org/webdev/files/2012/05/test-manifest.jpg" alt="" title="Test Manifest" width="550" height="176" class="aligncenter size-full wp-image-2732" /></p>
<h3>AppCloudy</h3>
<p>gkoberger&#8217;s next, fantastic project is a dead-simple way to <strong>deploy open web apps</strong> that integrates with github. It takes your project&#8217;s source code, generates a manifest and appcache file, compiles LESS and coffeescript files, and much more! And if that wasn&#8217;t enough yet, it also works on both the Mozilla Marketplace and the Chrome Web Store. Check it out at <a href="http://appcloudy.com/">appcloudy.com</a>.</p>
<p><img src="http://blog.mozilla.org/webdev/files/2012/05/AppCloudy.jpg" alt="" title="AppCloudy" width="550" height="272" class="aligncenter size-full wp-image-2730" /></p>
<h3>SmartSync for Shipyard JS</h3>
<p>seanmonstar is working on a new feature for his <a href="http://seanmonstar.github.com/Shipyard/">Shipyard JS</a> JavaScript framework: <strong>SmartSync</strong>. It enables the developer to provide a backup storage provider for when the browser is offline rather than just failing to interact with the server and making the application useless until network connection is restored. This will be particularly useful in mobile environments, enabling the user to make local changes to their application, which will be buffered until the device goes back online, at which time the actions will automatically be uploaded to the server. The feature is still developed in a feature branch, but is expected to land in Shipyard&#8217;s main code base soon.</p>
<h3>Status of Project Petri</h3>
<p>peterbe gives a quick update on the status of Mozilla&#8217;s <a href="https://wiki.mozilla.org/Petri">Project Petri</a>, <strong>Platform-as-a-Service</strong> and <strong>Infrastructure-as-a-Service</strong> for Mozilla developers, based on CloudFoundry (&#8220;VMWare-equivalent of Heroku&#8221;) and Eucalyptus (an open Amazon EC2 clone), respectively. They are facing some unique challenges deploying <a href="http://playdoh.readthedocs.org/">Playdoh</a>-based Django projects to CloudFoundry.</p>
<h3>ArtMaker</h3>
<p>Also known as <em>Drawing for people who can&#8217;t draw</em>, lorchard is working on a little <strong>collage maker</strong> written fully in JavaScript. You can stack various cliparts on top of each other and manipulate them, and finally export the result as a PNG file or send it straight to imgur. The tool is particularly useful for artistically challenged people who&#8217;d like to generate <a href="http://badg.us/">badges</a>, or for making a logo for your add-on or open web app. Les has a <a href="http://static.lmorchard.com/art-maker/demo.html">demo up on his domain</a> and would love you to <a href="https://github.com/lmorchard/art-maker">fork this on github</a>!</p>
<p><img src="http://blog.mozilla.org/webdev/files/2012/05/art-maker.jpg" alt="" title="Art Maker" width="550" height="274" class="aligncenter size-full wp-image-2731" /></p>
<h3>The video</h3>
<p>If you&#8217;d rather watch it for yourself, here you go:</p>
<p><br />
  <a target="_blank" href="http://vid.ly/9c2u0n"><br />
    <img src="http://cf.cdn.vid.ly/9c2u0n/poster.jpg" /><br />
  </a><br />
</p>
<p>We hope you enjoyed this month&#8217;s Beer and Tell and will join us again in June! If you have any questions, remarks, or concerns, don&#8217;t hesitate to comment on this post!</p>]]></description>
    <link><![CDATA[http://blog.mozilla.org/webdev/2012/05/29/mozilla-webdevs-beer-and-tell-may-18-2012/]]></link>
    <pubDate>2012-05-29 20:05:30</pubDate>
  </item>
  <item>
    <title><![CDATA[Wesley Chun: Tuples aren't what you think they're for]]></title>
    <description><![CDATA[<div>While I'm happy that the number of Python users continues to grow at a rapid pace and that there are many tutorials added each day to support all the newbies, there are a few things that make me cringe when I see them.</div><div><br /></div><div><span>One example of this is seeing a Python college textbook (you can tell by its retail price) produced by a big-name publisher (one of the largest in the world which shall remain unnamed) that instructs users (of Python 2), to get user command-line input using the </span><code>input()</code><span> function! Clearly, this is a major faux pas, as most Python users know that it's a security risk and that </span><code>raw_input()</code><span> should always be used instead (and the main reason why </span><code>raw_input()</code><span> replaces and is renamed as </span><code>input()</code><span> in Python 3).</span></div><div><br /></div><div>Another example is this <a href="http://pythoncentral.org/lists-and-tuples">recent article on lists and tuples</a>. While I find the content useful in teaching new Python developers various useful ways of using slicing, I disagree with the premise that tuples...</div><div><ol><li><span>along with lists are two of Python's most popular data structures</span></li><li><span>are mostly immutable but there are workarounds, and</span></li><li><span>should be used for application data manipulation</span></li></ol></div><div><br /></div><div><span>I would says lists and </span><i>dictionaries</i> are the two most popular Python data structures; tuples shouldn't even be in that group. In fact, I would even argue that tuples shouldn't be used to manipulate application data at all, as that wasn't what they were generally created for. (If this was the case, then why not have lists with a read-only flag?)</div><div><br /></div><div>The main reason why tuples exist is to get data to and from function calls. Calling a foreign API or 3rd-party function and want to pass in a data structure you know can't be altered? Check. Calling any function where you want to pass in only one data structure (instead of separate variables)? Use "*" and you're good to go. Previously worked with a programming language that only allowed you to return a single value? Tuples are that <i>one</i> object (think of it as a single shopping bag for all your groceries).</div><div><br /></div><div><span>All of the manipulations in the post on getting around the immutability are superfluous and not adhering to the best practice of </span><i>not</i> using tuples as a data structure. I mean, this is not a strict rule. If you're needing a data structure where you're not going to make any modifications and desire slightly better performance, sure a tuple can be used in such cases. This is why in Python 2.6, for the first time "evar," tuples were given methods!</div><div><br /></div><div><span>There was never any need for tuples to have methods because they were immutable. "Just use lists," is what we would all say. However, lists had a pair of read-only methods (</span><code>count()</code><span> and </span><code>index()</code><span>) that led to inefficiencies (and poor practices) where developers used tuples for the reason we just outlined but needed to either get a count on how many times an object appeared in that sequence or wanted to find the index of the first appearance of an object. They would have to convert that tuple to a list, just to call those methods. Starting in 2.6, tuples now have those (and only those) methods to avoid this extra nonsense.</span></div><div><span><br /></span></div><div><span>So yes, you can use tuples as user-land data structures in such cases, but that's really it. For manipulation, use lists instead. As stated at the top, I'm generally all for more intro posts and tutorials out there. However, there may be some that don't always impart the best practices out there. Readers should always be alert and question whether there are more "Pythonic" ways of doing things. In this case, tuples should <i>not</i> be one of the "[two] of the most commonly used built-in data types in Python...."</span></div><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/6940043312015460811-2342481373121234909?l=wescpy.blogspot.com" alt="" /></div>]]></description>
    <link><![CDATA[http://wescpy.blogspot.com/2012/05/tuples-arent-what-you-think-theyre-for.html]]></link>
    <pubDate>2012-05-29 15:52:42</pubDate>
  </item>
  <item>
    <title><![CDATA[Vern Ceder: How Not to Get a (Python) Job &#8211; a rant]]></title>
    <description><![CDATA[<p><strong>How Not to Get a (Python) Job &#8211; a rant </strong></p>
<p>At PyCon 2011, Brian Moloney (of Imaginary Landscape here in Chicago) gave a talk titled <strong>&#8220;</strong><a href="http://blip.tv/pycon-us-videos-2009-2010-2011/pycon-2011-getting-the-job-the-do-s-and-don-ts-of-landing-a-python-job-4898967" target="_blank">How to Get A Python Job&#8221;</a>. It wasn&#8217;t really so much about getting specifically a Python job as about how to land any job. It was the same sort of advice you can find in a lot places &#8211; hints on how (not) to apply, how (not) to present yourself, how (not) to interview, how (not) to impress interviewers, and so on. If you’re looking for a job, go watch it and take his advice very seriously.</p>
<p>I went to Brian’s talk because I had just found my own Python job and I was curious about his perspective. I had started my own job search with my fair share of negatives &#8211; the economy was in the toilet, I was over 50, I didn’t have much formal training, my experience (in private education) wasn&#8217;t exactly mainstream, etc. And yet within 3 months of sending out my first resumé I had a job, and even had to turn down other offers. Even as I settled into my new job, I was frequently contacted by recruiters looking for Python programming help. And yet, I’ve heard many people complaining quite vocally about how difficult it was (and is) to find programming jobs in general and Python jobs in particular.</p>
<p>As the IT director and lead developer at a startup trying to grow its tech staff, I’ve been heavily involved in searching for and interviewing developers. In that process I’ve seen people of all ages and backgrounds painfully ignore the basics of getting a job. So the idea behind this post is to put one more voice out there, sharing some of the things that make me not want to hire an applicant.</p>
<p><strong>Here are the things that make crazy. </strong>Take from them what you will.</p>
<p><strong>Not knowing the market</strong>. Several candidates have said, “it seems like no one is looking for Python people.” Say <em>what</em>? I get called regularly by recruiters looking for Python developers. We’ve been searching for a Python dev for <em>months</em>. Admittedly, the market is better for more experienced people and you might need to relocate, but even junior Python dev positions are going begging. Ask any recruiter, we’re a hot commodity. When someone tells me that no one is hiring for Python, that tells me one of two things&#8230; either that person doesn’t know the job market (at least around here), or they aren’t really a Python developer. In the first case, I’m a pretty firm believer that the responsibility for finding jobs lies with the job <em>seeker</em> and not having done research on the market it a bad sign. If you don’t care enough to do research to find your own career, why should I expect that you’ll have the initiative to solve problems and help our team move forward? And the alternative is worse &#8211; in a market where knowing how to spell the word “Python” (at least on a resumé) should get you at least a few calls, not getting any traction is a red flag.</p>
<p><strong>Not knowing the craft.</strong> This is so obvious that it shouldn’t need saying&#8230; except for the fact that it needs saying. “If you’re applying for a Python programming job, you should know as much as you can about Python and programming.” That means a basic understanding of the language, some basic knowledge of programming, some familiarity with the common or hot tools and technologies, etc. Obviously the depth of that understanding will vary depending on your experience, and for junior positions, particularly, you’re not expected to know everything, but you still should have some idea of the field.</p>
<p>I’ve interviewed candidates who couldn’t tell me how they would approach a problem, or what libraries they would use (or even <em>have</em> used), who’ve never even heard of Django, and so on. I’m no fan of springing little programming puzzles on candidates, since to my mind that mostly tests the ability to solve little puzzles, and I don’t expect lengthy dissertations on advanced programming topics, but I do expect you to be able to know the basics of coding and Python syntax, to have at least a nodding familiarity with current technologies, and to be able to discuss the approaches, tools and pitfalls involved in some of the coding you’ve done.</p>
<p>And speaking of the coding you’ve done, particularly for junior developers, you may not have done that much professionally. <em>However</em>, if you haven’t done <em>anything</em> outside of classwork, I’m going to be pretty skeptical. There are tons of opportunities to get involved in open source projects, to create your own web site, to help with something for a business, a club, or even just scratch your own personal software “itch.” It doesn’t matter how big or how successful your projects were, what matters to me is that you’re interested enough to be in the game on your own time.</p>
<p><strong>Not knowing us (and the job).</strong> It’s been said before, but if you don’t care enough to do some research and thinking about us and the position before you come in for an interview, why should we think you’ll care once you’re hired? You’ve got the job description, probably some names of people at the company, and the entire Internet as resources. Even if you don’t have absolutely all the information, you should be able to find out enough to ask questions and maybe even float trial solutions. Why do you do x? How do you deal with issue y? Have you ever thought of trying z to solve this problem? Even if you’re completely wrong about your assumptions, the very fact that you’re thinking about our business is very compelling. If you want to be really sneaky talk about how “we” might solve some of those problems together.</p>
<p>And speaking of sneaky (not really, since it’s clear if you’ve done it or not), if you know who you’ll be interviewing with, look the <em>people</em> up online. Google and LinkedIn are your friends here. At worst you’ll have a feeling of control during the interview and at best you can work in a comment or question relevant to the interviewer’s background, which is almost always good. I’m not going to support hiring you just because you looked at my LinkedIN profile, but it does tell me you cared enough to do some research, and that’s a good thing.</p>
<p><strong>Not selling yourself.</strong> Don&#8217;t go into your shell &#8211; there <em>is</em> a job open and somehow you’ve gotten an interview. So take advantage of it! You may be an introvert, it may be hard to talk about yourself, or maybe you just don’t think you <em>should</em> have to &#8220;market&#8221; yourself. Whatever&#8230; but in this situation you’ve really got to go for it. Show us how interesting you are, how much you care about the work, how cool you think the job is, how much you would bring to the team. If we hire you, we&#8217;ll have to work with you every day, so why should we look forward to that? (In a business sense, of course &#8211; promising to keep everyone loose with dirty jokes is probably not be the way to go here.)</p>
<p>We can only hire a few people and we need to get a lot of stuff done. We have lots of problems crying out for solutions so we want someone who is eager to tackle those problems and has some chance of succeeding. <a href="http://www.joelonsoftware.com/articles/GuerrillaInterviewing3.html" target="_blank">As Joel Spolsky succently put it</a>, “smart and gets things done.&#8221; You may not have the exact sklls to fix every problem at this moment, but that’s not the entire point &#8211; as a startup <em>none</em> of us had the exact skillset for this business when we started. But all of us were ready to dig in, we figured it out fast, and we got the job done. And that’s the sort of person we need.</p>
<p>Note: this is not the same as emphasizing how good this job would be for you. I understand that you want to move from that old job to a new, more interesting area. I applaud the fact that you just love to learn new things. I’m totally on board with how wonderful this opportunity would be for you&#8230; but we need to move and scrub a ton of data, polish the UI, analyze customer behavior, <em>and</em> keep thinking of new ways to stay ahead of the game. How are you going to help us do that?</p>
<p><strong>Now I have a dare for you.</strong> Let me end this lengthy rant with a challenge &#8211; if you’re a junior Python developer willing to work in the Chicago area, I dare you to send us your resumé. We&#8217;re Zoro Tools, Inc and you can send it to either Bruce Simmons, our recruiting lead (bruce.simmons&lt;AT&gt;zorotools.com), or me (vernon.ceder&lt;AT&gt;zorotools.com). If you take all of the above to heart we’ll be bowled over and have no choice but to hire you. That’ll serve me right for pontificating on hiring.</p>
<p>[edited to add company name and contact info]</p>
<br />Filed under: <a href="http://learnpython.wordpress.com/category/programming/">Programming</a>, <a href="http://learnpython.wordpress.com/category/python/">Python</a> Tagged: <a href="http://learnpython.wordpress.com/tag/programming-job/">programming job</a>, <a href="http://learnpython.wordpress.com/tag/python/">Python</a>, <a href="http://learnpython.wordpress.com/tag/python-job/">Python job</a>, <a href="http://learnpython.wordpress.com/tag/tech-hiring/">tech hiring</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/learnpython.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/learnpython.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/learnpython.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/learnpython.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/learnpython.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/learnpython.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/learnpython.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/learnpython.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/learnpython.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/learnpython.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/learnpython.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/learnpython.wordpress.com/166/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/learnpython.wordpress.com/166/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/learnpython.wordpress.com/166/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=learnpython.wordpress.com&blog=1158170&post=166&subd=learnpython&ref=&feed=1" width="1" height="1" />]]></description>
    <link><![CDATA[http://learnpython.wordpress.com/2012/05/27/how-not-to-get-a-python-job-a-rant/]]></link>
    <pubDate>2012-05-29 15:07:19</pubDate>
  </item>
  <item>
    <title><![CDATA[Luke Plant: Django's CBVs were a mistake]]></title>
    <description><![CDATA[<p>I've written before about the <a href="http://lukeplant.me.uk/blog/posts/class-based-views-and-dry-ravioli/">somewhat doubtful advantages of Class-Based Views</a>.</p>
<p>Since then, I've done more work as maintenance programmer on a Django project, and I've been reminded that library and framework design must take into account the fact that not all developers are experts. Even if you only hire the best, no-one can be an expert straight away.</p>
<p>Thinking through things more from the perspective of a maintenance programmer, my doubts about CBVs have increased, to the point where I recently tweeted that <a href="https://twitter.com/spookylukey/status/198452692522242049">CBVs were a mistake</a>.</p>
<p>So I thought I'd explain my reasons here. First, I'll look at the motivation behind CBVs, how they are doing at solving what they are supposed to solve, and then analyse the problems with them in terms of the Zen of Python.</p>
<h1 id="what-problems-do-cbvs-solve">What problems do CBVs solve?</h1>
<h2 id="customising-generic-views">Customising generic views</h2>
<p>People kept wanting more functionality and more keyword arguments to <a href="https://github.com/django/django/blob/stable/1.3.x/django/views/generic/list_detail.py">the list_detail views</a> (and others, but that those especially, as I remember). The alternative was large copy-and-paste of the code, so people were understandably wanting to avoid that (and avoid writing any code themselves).</p>
<p>So, we replaced them with classes that allows people to override just the bit they need to override. This eliminates the need for code duplication, and removes the burden of lots of feature requests for generic views.</p>
<p>Or does it? Instead of tickets for keyword arguments to list_detail, it seems we have a bunch of <a href="https://code.djangoproject.com/query?status=assigned&status=new&status=reopened&component=Generic+views&col=id&col=summary&col=status&col=owner&col=type&col=component&order=priority">other tickets asking for changes to CBVs</a>, many of which can't be implemented as mixins or subclasses.</p>
<p>One of the problems is that if the view calls anything else (e.g. a paginator class, or a form class), you have to provide hooks for how it calls it, which means implementing methods that can be overridden. If you forget any, or if the thing you are calling gains some new keyword arguments, you've got feature requests, or duplication because someone had to override a larger method just to change one aspect of it. If you don't forget any, you've got dozens of little methods to document.</p>
<p>Also, there are problems like this attempt to <a href="https://code.djangoproject.com/ticket/18158">mix FormView with ListView functionality</a>. Fixing this will end up with similar amounts of copy-paste, but in this case it requires a fair bit of debugging first to realise you have a problem.</p>
<p>So I'm not convinced CBVs have made much difference here.</p>
<h2 id="eliminating-flow-control-boilerplate">Eliminating flow control boilerplate</h2>
<p>The classic example is editing using a form. You see this pattern again and again using function based views (FBVs from now on):</p>
<pre class="sourceCode python"><code>from django.shortcuts import render

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            send_contact_message(form.cleaned_data['email'],
                                 form.cleaned_data['message'])
            return HttpResponseRedirect('/thanks/')
    else:
        form = ContactForm()

    return render(request, 'contact.html', {'form': form})
</code></pre>
<p>Without question this is tedious and annoying. CBVs reduce this to:</p>
<pre class="sourceCode python"><code>from django.views.generic.edit import ProcessFormView

class ContactView(ProcessFormView):
    form_class = ContactForm
    template_name = 'contact.html'
    success_url = '/thanks/'

    def form_valid(self, form):
        send_contact_message(form.cleaned_data['email'],
                             form.cleaned_data['message'])
        return super(ContactView, self).form_valid(form)
</code></pre>
<p>Much better!</p>
<p>However...</p>
<p>It's not really that much <strong>shorter</strong>. 8 lines compared to 11, ignoring imports. But now let's make it more realistic. We're going to have:</p>
<ul>
<li>Initial arguments to the form that are based on the request object.</li>
<li>Priority users get a form with the option to indicate 'urgent' status to message, which results in a text message as well as an email. The template is also rendered a bit differently for them and needs a flag.</li>
<li>URLs defined using <code>reverse</code> as they should be.</li>
</ul>
<p>FBV:</p>
<pre class="sourceCode python"><code>from django.core.urlresolvers import reverse
from django.shortcuts import render

def contact(request):
    high_priority_user = (not request.user.is_anonymous()
                          and request.user.get_profile().high_priority)
    form_class = HighPriorityContactForm if high_priority_user else ContactForm

    if request.method == 'POST':
        form = form_class(request.POST)
        if form.is_valid():
            email, message = form.cleaned_data['email'], form.cleaned_data['message']
            send_contact_message(email, message)
            if high_priority_user and form.cleaned_data['urgent']:
                 send_text_message(email, message)
            return HttpResponseRedirect(reverse('contact_thanks'))
    else:
        form = form_class(initial={'email': request.user.email}
                                  if not request.user.is_anonymous() else {})

    return render(request, 'contact.html', {'form': form,
                                            'high_priority_user': high_priority_user})
</code></pre>
<p>CBV:</p>
<pre class="sourceCode python"><code>from django.core.urlresolvers import reverse_lazy
from django.views.generic.edit import ProcessFormView

class ContactView(ProcessFormView):
    template_name = 'contact.html'
    success_url = reverse_lazy('contact_thanks')

    def dispatch(self, request, *args, **kwargs):
        self.high_priority_user = (not request.user.is_anonymous()
                                   and request.user.get_profile().high_priority)
        return super(ContactView, self).dispatch(request, *args, **kwargs)

    def get_form_class(self):
        return HighPriorityContactForm if self.high_priority_user else ContactForm

    def get_initial(self):
        initial = super(ContactView, self).get_initial()
        if not request.user.is_anonymous():
            initial['email'] = request.user.email
        return initial

    def form_valid(self, form):
        email, message = form.cleaned_data['email'], form.cleaned_data['message']
        send_contact_message(email, message)
        if self.high_priority_user and form.cleaned_data['urgent']:
             send_text_message(email, message)
        return super(ContactView, self).form_valid(form)

    def get_context_data(self, **kwargs):
        context = super(ContactView, self).get_context_data(**kwargs)
        context['high_priority_user'] = self.high_priority_user
        return context
</code></pre>
<p>(A few lines could be shaved by not using <code>super()</code> in a number of places, but only at the expense of future confusion/problems if a maintainer was expecting the normal declarative behaviour.)</p>
<p>Notice:</p>
<ol>
<li><p>I really want <code>high_priority_user</code> to be a local variable that is calculated once, and used in a couple of places. With a function, that's what I have. With a CBV, I have to simulate it using an attribute on self. I also need to override the <code>dispatch()</code> method just to create it. These are both ugly hacks.</p></li>
<li><p>The CBV version is extremely noisy, due to all the calls to <code>super()</code>. This would be improved in Python 3 (at the expense of a rather magical <code>super()</code> builtin), but is still far from perfect. Every time you override a method, you have to mention it twice.</p></li>
<li><p>The CBV version is now significantly longer - 24 non-blank lines compared to 17. Since I'm using the same APIs for requests and forms, and doing the same thing, this can only mean that the amount of boilerplate has significantly increased. Sure, I've removed the flow control boilerplate, but must have added some other type.</p></li>
<li><p>Even if you know the Form API very well, you are going to have to look up the docs or the source code to find <code>get_initial()</code> etc. and ensure you get the signature correct. You have to know two sets of APIs to use a form, instead of one.</p></li>
<li><p>In the CBV, flow control is totally hidden. In the process of abstracting away the duplication, we've also hidden the order of execution. I've ordered my methods in the order they are called (I think), but that may or may not be obvious to anyone else, and nothing forced me to do it.</p></li>
<li><p>Because of the last point, it is massively more difficult to debug. Which of the two would you rather maintain? Which do you think a maintenance programmer, who has never seen this code before, would rather maintain?</p>
<p>To understand what is going on, you've got an intimidating stack of base classes to navigate, compared to a single function.</p></li>
</ol>
<p>The fundamental problem here is that Python sucks at implementing custom flow control. Not many languages shine here. Ruby has blocks, which help. Haskell has a pretty good story due to a combination of succinct function definition, lazy evaluation and the way that IO works. Lisp has macros. But with Python, we are limited to: abusing generators, abusing the <code>with</code> statement, or classes and the <a href="http://en.wikipedia.org/wiki/Template_method_pattern">template method design pattern</a> (which is basically what CBVs use).</p>
<p>I think we decided to use the latter because it's one of the only options we've got, but failed to notice that it's just not very good.</p>
<p>There are worse things that can happen with shifting requirements. What if you want two different forms on the same page? I've done this on more than one occasion, and it can be a useful thing — when you present the user with two different courses of action, and you've got completely different info they need to fill in.</p>
<p>It would be a nightmare to get <code>CreateView</code> or <code>UpdateView</code> to do this. You will either produce a monstrosity, or you'll have to start from scratch with an FBV. You've been seduced down a tempting, calm stretch of water, and then left high and dry when you come to the end of what CBVs offer. If you start with an FBV, it's an easy change.</p>
<p>Overall, when I work on CBVs, even views I've created, I start to feel like I'm working on a classic <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.page.aspx">ASP.NET Page class</a>. It is bringing back painful memories! We’re not as bad as that yet, but methods that simply modify some data on <code>self</code> are a code-smell that we are heading in that direction.</p>
<p>Another way of looking at it is that with CBVs, views have become an instance of the ‘framework pattern’ instead of the ‘library pattern’. With a framework, your application code gets called by the framework code, and you can easily end up having to <a href="http://blogs.thesitedoctor.co.uk/tim/2006/06/30/Complete+Lifecycle+Of+An+ASPNet+Page+And+Controls.aspx">understand how the framework is implemented</a>.</p>
<p>With a library, the library code gets called by your application code, and this is in general much more flexible, much easier to document and much easier to debug. We ought to be moving Django more in the direction of a library.</p>
<p>With the comparison to ASP.NET, I'm also basically saying CBVs are not Pythonic. I'll back up this claim in terms of selected parts of the Zen of Python.</p>
<h1 id="are-cbvs-pythonic">Are CBVs Pythonic?</h1>
<h2 id="beautiful-is-better-than-ugly">Beautiful is better than ugly</h2>
<p>This is a subjective one, but the noise of all the <code>super()</code> calls, <code>get_context_data()</code> compared to a simple <code>{}</code> etc. is ugly to me.</p>
<h2 id="simple-is-better-than-complex">Simple is better than complex</h2>
<p>Let's notice, first off, that FBVs are simpler than CBVs, according to the basic meaning of having fewer parts.</p>
<p>A class is a datastructure with attributes and functions attached. A function is just a function. So a class is more complex than a function. If we ever use a class where a function would work, we have to justify the additional complexity.</p>
<h2 id="complex-is-better-than-complicated">Complex is better than complicated</h2>
<p>Are CBVs complicated? Just read the Django source if you think they are not.</p>
<p>In one app I wrote, I had a mixin that implemented a bit of common flow control for forms — namely it returned a JSON response with validation errors for certain types of requests. This meant I didn't need separate views for the AJAX validation, and with CBVs I eliminated all the boilerplate. Great!</p>
<p>Well, it was, until I found a crazy problem to do with the order in which different base classes set things up. To solve my problem, I ended up writing this:</p>
<pre class="sourceCode python"><code># MRO problem: we need BaseCreateView.post to come first in MRO, to
# provide self.object = None, then AjaxyFormMixin must be called before
# ProcessFormView, so that the right thing happens for AJAX.

class AjaxMroFixer(type):

    def mro(cls):
        classes = type.mro(cls)
        # Move AjaxyFormMixin to one before last that has a 'post' defined.
        new_list = [c for c in classes if c is not AjaxyFormMixin]
        have_post = [c for c in new_list if 'post' in c.__dict__]
        last = have_post[-1]
        new_list.insert(new_list.index(last), AjaxyFormMixin)
        return new_list
</code></pre>
<p>It's a metaclass, and implements the <code>mro()</code> method that allows you to override the method order resolution. I am not proud of this code. (For those who don't get English understatement, please understand what I'm saying: this code is horrific). Before writing this code, I didn't know that the <code>mro()</code> method existed. Although I value the education, if a framework forces you to learn about <code>type.mro()</code> and implement it, it is doing something wrong.</p>
<h2 id="flat-is-better-than-nested">Flat is better than nested</h2>
<p>The hierarchy of classes is certainly a form of nesting, whereas functions are flat. I think CBVs might be considerably better if you started by writing your own, so that you had base classes that did everything you needed, but nothing more, and ended up with a very flat hierarchy.</p>
<h2 id="readability-counts">Readability counts</h2>
<p>Get some people who don't know Django to read <code>ContactView</code> above and figure out what it does, and some others to feed the function version, and see who has the easier time. There is no contest here.</p>
<h2 id="explicit-is-better-than-implicit">Explicit is better than implicit</h2>
<p>With a CBV, by inheriting from a class you are inheriting all the behaviour of that class, and all its parent classes. You could argue this is explicit, since you've explicitly indicated the base class, but you haven't indicated all the parent classes — they come automatically. So it's more like an implicit request in practice.</p>
<p>Of course, this is always true with OOP to some extent — you are inheriting a bunch of behaviour precisely because you don't want to define it again. But let's notice that it does have its downsides.</p>
<p>For example, let's play spot the difference between the following two views — an FBV:</p>
<pre class="sourceCode python"><code>from django.shortcuts import render

def my_view(request):
    return render(request, &quot;my_template.html&quot;, {})
</code></pre>
<p>and a CBV:</p>
<pre class="sourceCode python"><code>from django.views.generic import TemplateView

class MyView(TemplateView):
    template_name = &quot;my_template.html&quot;
</code></pre>
<p>Can you see the important difference? Try to answer before reading on.</p>
<p>I'm talking only about the functional differences when this view is accessed by a client, not differences of code organisation or re-use or performance.</p>
<p>Well, <code>TemplateView</code> inherits from <code>View</code> which provides a <code>dispatch()</code> method, and <code>TemplateView</code> provides a <code>get()</code> method which will handle all GET (and HEAD) requests, by the logic defined in <code>View.dispatch()</code>. However, neither defines a <code>post()</code> method, which means that you will get a &quot;405 Method Not Allowed&quot; error if you try POST or other HTTP verbs, to the CBV view, whereas you will get a 200 with the FBV.</p>
<p>In the CBV, all of this logic has been invoked implicitly. Nothing in what I wrote was an explicit request for 405s for POST requests, but I got it because I inherited from <code>TemplateView</code> — even though using a template does not imply that behaviour.</p>
<p>(By the way, this issue caused a real problem in a site I wrote, which was easily debugged because I knew a lot about the internals of CBVs, and therefore easily fixed, but it still adds noise to my class — code that can only be explained by reference to some inherited behaviour I didn't really want).</p>
<p>Of course, as already mentioned, you can say the same thing whenever you inherit from a class. But, in my opinion, it is one of the disadvantages of OOP, and it is showing itself here. The question is: do the advantages of inherited behaviour outweigh the disadvantages of implicit behaviour?</p>
<h2 id="there-should-be-one-way-to-do-it">There should be one way to do it</h2>
<p>I already mentioned one case where the CBV method is just not going to work for you, or is not going to be worth it — needing two different forms on the same page. But in the real views I write, I suspect probably the majority would not fit easily into a CBV.</p>
<p>So, in your project you now need both FBVs and CBVs — you've got two ways to do it. When a maintenance programmer comes along, and needs to do some similar work that involves a form, they will be confused. Which pattern do they start from?</p>
<p>The simple way to avoid this is to avoid the less flexible solution — avoid using CBVs.</p>
<p>So simply having two different ways of building up views is a violation of this principle, but <strong>within</strong> CBVs there are also instances.</p>
<p>First, there are also problems with the attempt to use declarative style, which is perhaps the most attractive feature of the CBV API. So, you need initial arguments to your form? Just define the <code>initial</code> attribute on your class. Unless, however, you need it to be dynamic — you'll have to define <code>get_initial()</code> instead.</p>
<p>Also, it often isn't obvious where to add certain bits of code. There is often more than one choice of method to override when you come to add a little bit of functionality e.g. <code>get()</code> or <code>dispatch()</code>, and which you choose sometimes has subtle implications, and sometimes doesn't matter. With FBVs, two different Django developers tasked with the same modification to an existing view would often produce identical or nearly identical patches, but I suspect that would be rarer with CBVs.</p>
<h2 id="if-the-implementation-is-hard-to-explain-its-a-bad-idea">If the implementation is hard to explain, it's a bad idea</h2>
<p>Looking at the implementation, you'll find things like <code>MultipleObjectTemplateResponseMixin</code>, as well as <code>MultipleObjectMixin</code> and <code>TemplateResponseMixin</code>, and the former is not just the composition of the other two. This is just one of many signs that things are going wrong. If you can really compose behaviour just by adding mixins, <code>MultipleObjectTemplateResponseMixin</code> should not be needed. Explaining things like this is hard, and the reason is that you just can't build up complex views using classes and mixins.</p>
<h1 id="conclusion">Conclusion</h1>
<p>Overall, I think CBVs make:</p>
<ul>
<li><p>very simple views slightly shorter, much cleaner (and significantly harder to debug, but you don't need to debug them because they are simple);</p></li>
<li><p>views of medium complexity significantly longer, with more boilerplate and noise and much harder to debug;</p></li>
<li><p>views of high complexity almost impossible.</p></li>
</ul>
<p>You only gain for the simple views, but they were simple anyway, just slightly tedious. Is this advantage really enough to outweigh the disadvantages I've listed?</p>
<p>To be honest, I regret dropping the function based generic views for CBVs. There was an alternative solution to the tickets asking for them to do more: WONTFIX.</p>
<p>Generic views were simple shortcuts for common problems. They didn't actually involve very much code, and if you needed to duplicate some of it you weren't duplicating much. We should have just said: this is what generic views do, if you need them to do something else then write your own. Because that is what you have to say with class based generic views anyway, just slightly later.</p>
<p>Regarding going forward, I say: stop the rot.</p>
<p>If you're starting a new project, I recommend avoiding CBVs, or just wrapping them in thin functional wrappers, like <a href="https://gist.github.com/2596285">this one for ListView</a> (or, with <a href="https://github.com/ericflo/django-pagination">django-pagination</a> a simple 3-line view function is probably all you need and is actually easier than subclassing <code>ListView</code>).</p>
<p>For Django core, let's fix up the main problems and bugs CBVs have, and then leave them as solutions to simple problems.</p>
<p>But please: let's not move everything in Django-world — whether Django core/contrib or resuable apps — to CBVs. Just use a function, and <a href="http://pyvideo.org/video/880/stop-writing-classes">stop writing classes</a>.</p>]]></description>
    <link><![CDATA[http://lukeplant.me.uk/blog/posts/djangos-cbvs-were-a-mistake/]]></link>
    <pubDate>2012-05-29 14:44:11</pubDate>
  </item>
  <item>
    <title><![CDATA[Grig Gheorghiu: A sweep through my Instapaper for May 2012]]></title>
    <description><![CDATA[Here are some of the presentations/blog posts/articles I read this month, as saved in my Instapaper account. Maybe you'll find something useful in there too.<br /><ul><li>"<a href="http://codeascraft.etsy.com/2012/05/22/blameless-postmortems/">Blameless PostMortems and a Just Culture</a>" -- John Allspaw describes the post mortem process at Etsy, in particular how it encourages engineers to own up to their mistakes and to help others avoid them, all in a safe and blame-free environment</li><li>"<a href="http://blog.sprint.ly/post/22794189287/nerd-alert-sprint-lys-continuous-integration">Sprint.ly's Continuous Integration</a>" -- good overview of what should be by now industry-standard methods and tools for rapid deployments and continuous integration</li><li>"<a href="http://highscalability.com/blog/2012/5/16/big-list-of-20-common-bottlenecks.html">Big List of 20 Common Bottlenecks</a>" -- via the super useful High Scalability blog, a list of bottlenecks that you will hit one way or another if you do any serious high-volume systems work</li><li>"<a href="http://queue.acm.org/detail.cfm?id=1394128">BASE: An ACID alternative</a>" -- Dan Pritchett from EBay coined the term BASE (basically available, soft state, eventually consistent) to compare and contrast NoSQL systems with traditional ACID-based relational databases; very good overview of these types of systems</li><li>"<a href="http://cs-www.cs.yale.edu/homes/dna/papers/calvin-sigmod12.pdf">Calvin: Fast Distributed Transactions&nbsp;for Partitioned Database Systems</a>" (PDF) -- Daniel Abadi and collaborators write about a distributed transaction mechanism that can sit on top of non-transactional storage systems, transforming them into scalable, highly-available ACID databases</li><li>"<a href="http://drnicwilliams.com/2012/04/16/creating-a-bosh-from-scratch-on-aws/">Creating a BOSH from scratch on AWS</a>" -- great tutorial from Dr Nic from Engine Yard on installing CloudFoundry's BOSH tool on AWS</li><li>"<a href="http://www.infoq.com/presentations/Amazon-com-Journey-to-the-Cloud">Amazon's Journey to the Cloud</a>" -- very good presentation by John Rauser on the long and winding road taken by Amazon from their beginnings running on 1 machine to the launch of AWS technologies</li><li>"<a href="https://speakerdeck.com/u/kellan/p/engineering-change">Engineering Change</a>" -- short but very insightful presentation by Etsy's CTO Kellan Elliott-McCrea on continuous deployment strategies and metrics-driven development</li><li>"<a href="http://www.macroresilience.com/2011/12/29/people-make-poor-monitors-for-computers/">People Make Poor Monitors for Computers</a>" -- eye-opening article on the dangers on relying on highly automated and sophisticated monitoring systems; when they fail, human operators are expected to jump in and fix the issues, but unfortunately those rare issues are extremely hard to diagnose and fix by humans who have lost their edge by relying on the automated systems in the first place!</li><li>"<a href="http://pydata.github.com/vbench/">vbench - benchmarking performance through time</a>" -- from Wes McKinney's Panda project, vbench is a lightweight Python library for measuring code performance and catching performance regressions</li><li>"<a href="http://blog.thestateofme.com/2012/04/16/big-data-a-little-analysis/">Big Data -- a little analysis</a>" -- switching gears to Big Data, here's a good overview/taxonomy of types of problems in this space, based on data volume and algorithm complexity, courtesy of Chris Swan</li><li>"<a href="http://gigaom.com/cloud/the-unsexy-side-of-big-data-6-tools-to-manage-your-hadoop-cluster/">The unsexy side of big data: 5 tools to manage your Hadoop cluster</a>" -- some tools I had never heard of for managing Hadoop clusters, including <a href="http://incubator.apache.org/ambari/">Apache Ambari</a> and <a href="http://incubator.apache.org/mesos/">Apache Mesos</a></li><li>"<a href="http://www.r-bloggers.com/online-resources-for-handling-big-data-and-parallel-computing-in-r/">Online resources for handling big data and parallel computing in R</a>" -- from the R-bloggers blog aggregator, a useful collection of links on mostly parallel computing with R</li><li>"<a href="http://practicalquant.blogspot.com/2012/05/much-to-like-about-hbasecon.html?m=1">Much to like about HBaseCon</a>" -- quick overview of some talks from last week's HBaseCon 2012</li></ul><div>I also want to give a shout-out here to <a href="https://twitter.com/#!/garethr">Gareth Rushgrove</a>, who publishes an email newsletter called 'Devops Weekly'. If you are working in this field, I highly recommend you <a href="http://devopsweekly.com/">subscribe</a> to it, as it is always full of interesting links and summaries to articles and tools.</div><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/9238405-7372343048201649924?l=agiletesting.blogspot.com" alt="" /></div>]]></description>
    <link><![CDATA[http://agiletesting.blogspot.com/2012/05/sweep-through-my-instapaper-for-may.html]]></link>
    <pubDate>2012-05-29 10:36:53</pubDate>
  </item>
  <item>
    <title><![CDATA[Philippe Normand: Implementing WebAudio in WebKit with GStreamer]]></title>
    <description><![CDATA[<p><a class="reference external" href="https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html">WebAudio</a> is a JavaScript API for processing and synthesizing audio in web applications. It has been implemented first in Google Chrome and later on in Safari. The intention behind this blog post is to explain
how other WebKit ports can support the <a class="reference external" href="https://bugs.webkit.org/show_bug.cgi?id=61355">WebAudio APIs using
GStreamer</a>. The <a class="reference external" href="http://webkitgtk.org">WebKit GTK+</a> port is already up to speed and the
<a class="reference external" href="http://trac.webkit.org/wiki/EFLWebKit">EFL</a> and <a class="reference external" href="http://trac.webkit.org/wiki/QtWebKit">Qt</a> ports are within reach as well.</p>
<p>The <a class="reference external" href="http://chromium.googlecode.com/svn/trunk/samples/audio/index.html">Chromium WebAudio demos</a> don't work yet in <a class="reference external" href="http://projects.gnome.org/epiphany/">Epiphany</a> because
WebKitGTK+ doesn't yet ship with WebAudio support enabled by default
and the WebView used by Epiphany doesn't yet enable the
<a class="reference external" href="http://webkitgtk.org/reference/webkitgtk/stable/WebKitWebSettings.html#WebKitWebSettings--enable-webaudio">enable-web-audio WebKitWebSetting</a>. However, for the brave people
willing to <a class="reference external" href="http://trac.webkit.org/wiki/BuildingGtk">build WebKitGTK+</a>, here are the steps to follow:</p>
<pre class="literal-block">
$ Tools/Scripts/build-webkit --gtk --web-audio
$ Tools/Scripts/run-launcher --gtk --enable-web-audio=TRUE http://chromium.googlecode.com/svn/trunk/samples/audio/shiny-drum-machine.html
</pre>
<p>I especially like the drum machine demo, pretty impressing stuff!  So,
back to the topic. Fortunately the WebAudio AudioContext was designed
to allow multiple platform backends in WebCore, I'm going to talk
about the GStreamer backend. It was first prototyped by <a class="reference external" href="http://falcosigh.wordpress.com/">Zan
Dobersek</a> and he kindly passed me on the task which I continued and
upstreamed in WebKit trunk.</p>
<p>The two biggest features of the backend are:</p>
<p>1. Decoding audio data from a media file or from a memory pointer and
pulling it into the WebAudio machinery of WebKit where it's going to
be processed by the WebAudio pipeline.</p>
<p>2. Getting back audio data as WAV from the WebAudio pipeline and play
it back :)</p>
<p>For the first step we use <a class="reference external" href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-base-plugins/html/gst-plugins-base-plugins-decodebin2.html">decodebin2</a> with data coming from either
filesrc or giostreamsrc. The decoded data is split in mono channels
using the <a class="reference external" href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-deinterleave.html">deinterleave</a> element, passed to appsinks and converted to
AudioChannels which internally store the data in FloatArrays. Every
AudioChannel is stored in an AudioBus instance which we pass onto
WebCore for further internal processing. The implementation can be
found in the <a class="reference external" href="http://trac.webkit.org/browser/trunk/Source/WebCore/platform/audio/gstreamer/AudioFileReaderGStreamer.cpp">AudioFileReaderGStreamer.cpp</a> file.</p>
<p>Internally the WebAudio stack also relies on our <a class="reference external" href="http://trac.webkit.org/browser/trunk/Source/WebCore/platform/audio/gstreamer/FFTFrameGStreamer.cpp">GStreamer FFTFrame</a>
implementation which uses the gst-fft library to perform Fast Fourier
Transforms.</p>
<p>Then let's talk about playback! Once the WebAudio stack has finished
processing data and if the web developer created an
<a class="reference external" href="https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#AudioDestinationNode">AudioDestinationNode</a> as part of his WebAudio pipeline, the user needs
to hear something playing :) As the mighty reader might guess the
magic is done in an <a class="reference external" href="http://trac.webkit.org/browser/trunk/Source/WebCore/platform/audio/gstreamer/AudioDestinationGStreamer.cpp">AudioDestinationGStreamer.cpp</a> file! I decided to
implement most of the logic about reading data from the AudioBus as a
GStreamer source element, called WebKitWebAudioSourceGStreamer. This
element takes every AudioChannel of the AudioBus, convert the
FloatArray data to GStreamer buffers, <a class="reference external" href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-interleave.html">interleave</a> the channels and
encode the whole as WAV data using the <a class="reference external" href="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-wavenc.html">wavenc</a> element. In the
AudioDestination GStreamer pipeline we then use this shiny source
element, parse the WAV data and pass it on the audio sink!</p>
<p>What's next in our roadmap?</p>
<ul class="simple">
<li>I'm not sure this source element was the correct approach
in the end, I think that at some point I'll just refactor it into
the AudioDestination implementation.</li>
<li>Port to GStreamer 0.11 APIs! This work is on-going already for the MediaPlayer.</li>
<li>There are still some bugs to fix, before I really feel confident
about enabling this feature by default. We should also add support
for reading data from the HTML5 Media elements.</li>
<li>The WebKit webaudio layout tests are almost passing on the build
bots, this work is <a class="reference external" href="https://bugs.webkit.org/show_bug.cgi?id=67187">on-going</a> as well.</li>
<li>Enable WebAudio by default in WebKitGTK's build and Epiphany,
targetting GNOME 3.6.</li>
</ul>
<p>I would like to thank <a class="reference external" href="http://igalia.com">Igalia</a> for allowing me to dedicate work time on this project :)</p>]]></description>
    <link><![CDATA[http://base-art.net/Articles/120/]]></link>
    <pubDate>2012-05-29 02:47:22</pubDate>
  </item>
  <item>
    <title><![CDATA[Montreal Python User Group: Montréal-Python 30: Nootropic Nutrients]]></title>
    <description><![CDATA[<p>If you listen to mainstream media and notorious market analysts, you are lead to believe that simply using Python is enough to make you deliver code ten times faster.</p>
<p>Obviously, this simplistic view of the world fails to take into account the <a href="http://www.usatoday.com/tech/science/environment/story/2012-01-30/pythons-florida-everglades/52893342/1">constant battle</a> with the U.S. Fish and Wildlife Service in the Everglades but most of all, it fails to take into account that the Python language itself is a very small contribution compared to the tools and the body of knowledge shared within the community.</p>
<p>Of course, we all understand that development is more than just writing code.  On June 12th, Montréal-Python is going to celebrate our unwritten lore with Nootropic Nutrients, a meeting on the Best Practices and tools in the Python world.</p>
<p>Can you claim a ten-fold speedup compared to developement with traditional languages?  Do you have hard-won secrets that you would like to share?  Come and tell us about your tools and stategies for efficiently and consistently delivering your projects on time.</p>
<p>We are looking for speakers for presentations ranging from 5 minutes to 40 minutes.<br />
If you are interested, send us an email to <a href="mailto:mtlpyteam@googlegroups.com">mtlpyteam@googlegroups.com</a> with a short description of your talk.</p>
<p>The meeting will follow the usual schedule, starting around 6:30pm and moving to the pub for the follow-up discussions around 8:30pm.</p>]]></description>
    <link><![CDATA[http://montrealpython.org/2012/05/mp30/]]></link>
    <pubDate>2012-05-29 02:10:26</pubDate>
  </item>
  <item>
    <title><![CDATA[Daniel Nouri: Kotti Werkpalast Sprint Wrap Up]]></title>
    <description><![CDATA[<div class="document">
<p>Last week's Kotti sprint in Berlin was full of win.  Here's a summary
of what we worked on.  (Sprinters: If I forgot to mention anything,
please let me know and I'll update.)</p>
<p>(Update: Saving a page on the demo site seems to be broken as we
speak.  Will fix soon.)</p>
<div class="contents topic" id="contents">
<p class="topic-title first">Contents</p>
<ul class="simple">
<li><a class="reference internal" href="http://danielnouri.org/notes/category/python/feed/index.xml#search-and-kotti-solr" id="id2">Search and kotti_solr</a></li>
<li><a class="reference internal" href="http://danielnouri.org/notes/category/python/feed/index.xml#snippets-slots-and-pyramid-snippets" id="id3">Snippets, slots and pyramid_snippets</a></li>
<li><a class="reference internal" href="http://danielnouri.org/notes/category/python/feed/index.xml#images" id="id4">Images</a></li>
<li><a class="reference internal" href="http://danielnouri.org/notes/category/python/feed/index.xml#rich-text-editing" id="id5">Rich text editing</a></li>
<li><a class="reference internal" href="http://danielnouri.org/notes/category/python/feed/index.xml#http-caching" id="id6">HTTP Caching</a></li>
<li><a class="reference internal" href="http://danielnouri.org/notes/category/python/feed/index.xml#paster-templates" id="id7">Paster templates</a></li>
</ul>
</div>
<a href="http://www.flickr.com/photos/77236500@N07/7267020452/" title="IMG_0663 by d1sk0, on Flickr"><img src="http://farm8.staticflickr.com/7234/7267020452_aa61aeccfc.jpg" width="500" height="374" alt="IMG_0663" /></a><div class="section" id="search-and-kotti-solr">
<h3><a class="toc-backref" href="http://danielnouri.org/notes/category/python/feed/index.xml#id2">Search and kotti_solr</a></h3>
<p>Andi (witsch), Marco and Nuno worked on adding search to Kotti.  Kotti
now has a search box at the top right of the site that searches the
'title' and 'description' fields of content in the database.  A
setting called <tt class="docutils literal">kotti.search_content</tt> allows the search function to
be overridden.  Which is where <a class="reference external" href="https://github.com/teixas/kotti_solr">kotti_solr</a> hooks in to provide search
through Solr.  kotti_solr has a buildout that installs Solr, and it's
already working, but will currently only search the same 'title' and
'description' fields.  (That is, it will need to grow adapters so that
we can extract all searchable text from content.)</p>
<p>The basic search has already landed in Kotti's master branch in Git
and will be available in the next version.  There's still a few issues
that need to be worked on here before that can happen though:</p>
<ul class="simple">
<li>Do permission checks with search results; at the moment search will
return all items, whether the user has permission to see them or
not.  (Maybe this is a good time to consider adding something like
CMF's <tt class="docutils literal">allowedUsersAndRoles</tt> index to Kotti's Node.)</li>
<li>Document the <tt class="docutils literal">kotti.search_content</tt> setting.</li>
</ul>
<p>We could also use some help in styling the search box and search
results better.  You can test drive the search on the <a class="reference external" href="http://kottidemo.danielnouri.org/">demo site</a>.</p>
</div>
<div class="section" id="snippets-slots-and-pyramid-snippets">
<h3><a class="toc-backref" href="http://danielnouri.org/notes/category/python/feed/index.xml#id3">Snippets, slots and pyramid_snippets</a></h3>
<p>Christian, Florian, Krille and Ibi worked on adding support for what
Wordpress calls <a class="reference external" href="http://codex.wordpress.org/Shortcode">Shortcodes</a>
and MoinMoin calls <a class="reference external" href="http://moinmo.in/HelpOnMacros">macros</a>.</p>
<p>With this, users will be able to insert codes like <tt class="docutils literal">[gallery]</tt> into
their pages and have these render to dynamic elements in the public
view.  Shortcodes may also take arguments like <tt class="docutils literal"><span class="pre">[table-of-contents</span>
level=3]</tt>.  We <a class="reference external" href="https://groups.google.com/d/topic/kotti/Kck0kYK3EkQ/discussion">discussed this idea</a>
back in February on the list.</p>
<p>The team decided they would move the core functionality behind what
they call <em>snippets</em> into a separate package <a class="reference external" href="https://github.com/fschulze/pyramid_snippets">pyramid_snippets</a>.  The idea is that
snippets behave like views with the advantage that they can be easily
pulled in via AJAX and be used in other places in the site, like in
the portlet columns.  The integration with Kotti is happening in the
<a class="reference external" href="https://github.com/chrneumann/Kotti/tree/snippets">snippets branch</a>.  Plans are to
add a button to TinyMCE that allows users to add snippets instead of
having to remember the codes and syntax.</p>
<p>We also want to eventually deprecate <a class="reference external" href="http://kotti.readthedocs.org/en/latest/developer-manual.html#module-kotti.views.slots">Kotti's slots</a>
and unify them with snippets so that slot renderers will become views
and can be used as snippets and vice versa.</p>
<a href="http://www.flickr.com/photos/77236500@N07/7267018542/" title="IMG_0660 by d1sk0, on Flickr"><img src="http://farm8.staticflickr.com/7105/7267018542_f8dc1f3850.jpg" width="500" height="374" alt="IMG_0660" /></a></div>
<div class="section" id="images">
<h3><a class="toc-backref" href="http://danielnouri.org/notes/category/python/feed/index.xml#id4">Images</a></h3>
<p>Anreas (disko) added a new Image type and image scaling to Kotti core.
He extracted these out of the nice <a class="reference external" href="https://github.com/disko/kotti_image_gallery">kotti_imagegallery</a> add-on that he had
written earlier.</p>
<p>Predefined image scales include <tt class="docutils literal">span1</tt> (60x120) to <tt class="docutils literal">span12</tt>
(1160x2320).  Additional image scales can be configured through the
<tt class="docutils literal">kotti.image_scales</tt> variables.</p>
</div>
<div class="section" id="rich-text-editing">
<h3><a class="toc-backref" href="http://danielnouri.org/notes/category/python/feed/index.xml#id5">Rich text editing</a></h3>
<p>Andreas (disko) and Daniel worked on improving the rich text editing
story for Kotti.  Based on the work done on images and scaling by
Andreas, they created <a class="reference external" href="https://github.com/dnouri/kotti_tinymce">kotti_tinymce</a>, which is an add-on that
provides image and file upload, browsing and insertion through
TinyMCE.</p>
<p>kotti_tinymce is actually based on the <a class="reference external" href="https://github.com/plone/Products.TinyMCE">Products.TinyMCE</a> add-on for Plone, and
uses the exact same JavaScript resources.  Only page templates and CSS
are overridden and the server-side AJAX hooks implemented to work with
Kotti.  (We were quite amazed at how well this worked out.)</p>
<p>One problem with kotti_tinymce is that there's no functional tests.
We've just verified that things are working by clicking through all
the dialogues manually.  Considering that Products.TinyMCE is evolving
separately and that we want to maintain upstream compatibility, we
really want to implement some browser-based functional tests to be
able to guarantee a reasonable level of stability.  These tests will
also help us fix the remaining bugs in kotti_tinymce.</p>
<p>You can try out the rich text editing improvements on the <a class="reference external" href="http://kottidemo.danielnouri.org/">demo
site</a>!</p>
</div>
<div class="section" id="http-caching">
<h3><a class="toc-backref" href="http://danielnouri.org/notes/category/python/feed/index.xml#id6">HTTP Caching</a></h3>
<p>Andreas (disko) and Daniel added <a class="reference external" href="https://github.com/Pylons/Kotti/blob/master/kotti/views/cache.py">HTTP caching</a>
into the Kotti core.  There's now a default caching policy which may
be overridden using the <tt class="docutils literal">kotti.caching_policy_chooser</tt> setting.  The
default policy is to not cache HTML, cache media for four hours, cache
static resources for a month and so on.</p>
<p>The http caching code is <a class="reference external" href="http://danielnouri.org/notes/2011/02/12/http-caching-for-the-masses/">based on code</a>
previously written by Daniel.</p>
</div>
<div class="section" id="paster-templates">
<h3><a class="toc-backref" href="http://danielnouri.org/notes/category/python/feed/index.xml#id7">Paster templates</a></h3>
<p>Marco and Tom worked on <a class="reference external" href="https://github.com/j23d/kotti_paster">kotti_paster</a> which Marco initially
started.  They've been working on a set of accumulative templates for
Kotti that are based around Buildout and try to define best practices
for different aspects of Kotti and Pyramid development for beginners.</p>
<a href="http://www.flickr.com/photos/77236500@N07/7267021654/" title="IMG_0665 by d1sk0, on Flickr"><img src="http://farm9.staticflickr.com/8016/7267021654_8c7124e8ac.jpg" width="500" height="374" alt="IMG_0665" /></a></div>
</div>]]></description>
    <link><![CDATA[http://danielnouri.org/notes/2012/05/28/kotti-werkpalast-sprint-wrap-up]]></link>
    <pubDate>2012-05-28 16:30:00</pubDate>
  </item>
  <item>
    <title><![CDATA[Ned Batchelder: Recursive dogma]]></title>
    <description><![CDATA[<p>This morning in the #python IRC channel, someone needed help with a recursive function:
</p><blockquote><div><p>
<b>Questioner:</b> i have a problem with a little recursive function<br />
<b>Questioner:</b> i create a list recursive of length 2**30 but i get a memory problem<br />
<b>Naysayer:</b> recursion in Python is almost always bad news<br />
<b>Questioner:</b> i have probs with high memory because i create too many too large list when i enter a value of 2**30 for N<br />
<b>RecursionFan:</b> recursion is awesome<br />
<b>RecursionFan:</b> it sounds like you're doing it wrong<br />
<b>Naysayer:</b> you should avoid recursion in python<br />
<b>RecursionFan:</b> why?<br />
<b>Naysayer:</b> There's this little thing called the stack<br />
<b>Questioner:</b> yeah i now the depth of my recursion, its just log(N)<br />
<b>Questioner:</b> but can somebody help me so this function can work for parameters of 2**30<br />
<b>RecursionFan:</b> there's this little thing called <a class="offsite" href="http://en.wikipedia.org/wiki/Tail_call">http://en.wikipedia.org/wiki/Tail_call</a><br />
<b>Naysayer:</b> yeah, and python doesn't have it<br />
<b>DeadPanda:</b> RecursionFan, does python optimise tail-recursion?<br />
<b>nedbat:</b> RecursionFan: Python doesn't do tail-call removal.<br />
<b>Naysayer:</b> DeadPanda: No<br />
<b>nedbat:</b> Naysayer: "you should avoid recursion" is a bit strong.  You need to understand the limitation.<br />
<b>nedbat:</b> Naysayer: Python is as good at recursion as C is at integer arithmetic.<br />
<b>Naysayer:</b> nedbat: It is good practice to avoid recursion in Python if you don't understand how it works.<br />
<b>nedbat:</b> Naysayer: it is good practice to avoid _____ in Python if you don't understand how it works.
</p>
</div></blockquote><p>(Names other than mine, nedbat, are changed.) 
    Before anyone's read Questioner's code, or even listened fully to his question,
    we're off on the usual rant against recursion in Python, and debates about tail-call elimination.
    As it happens, and as Questioner rightly understood, the problem is not about deep recursion:</p><blockquote class="code"><tt><span class="k">def</span>&#xA0;<span class="nf">computeHW</span><span class="p">(</span><span class="n">N</span><span class="p">):</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">if</span>&#xA0;<span class="n">N</span>&#xA0;<span class="o">==</span>&#xA0;<span class="mi">1</span><span class="p">:</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">return</span>&#xA0;<span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">else</span><span class="p">:</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">L</span>&#xA0;<span class="o">=</span>&#xA0;<span class="n">computeHW</span><span class="p">(</span><span class="n">N</span><span class="o">/</span><span class="mi">2</span><span class="p">)</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">L</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="mi">2</span><span class="o">*</span><span class="n">i</span>&#xA0;<span class="k">for</span>&#xA0;<span class="n">i</span>&#xA0;<span class="ow">in</span>&#xA0;<span class="n">L</span><span class="p">])</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">return</span>&#xA0;<span class="n">L</span>
<br /></tt></blockquote><p>Questioner wanted to call this function with 2**30, which is quite modest in terms of depth, 
    the stack will only get 30 levels deep.  But it's crazy in memory terms: it tries to allocate
    a list with a billion elements, but not before it's allocated and deallocated many many others,
    up to that size.</p><p>So yes, this function isn't going to work, but not because of tail-call optimization or its lack.
    We can change the function into a generator that still works recursively, but won't allocate
    any memory:</p><blockquote class="code"><tt><span class="k">def</span>&#xA0;<span class="nf">computeHW2</span><span class="p">(</span><span class="n">N</span><span class="p">):</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">if</span>&#xA0;<span class="n">N</span>&#xA0;<span class="o">==</span>&#xA0;<span class="mi">1</span><span class="p">:</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">yield</span>&#xA0;<span class="mi">1</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">else</span><span class="p">:</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">for</span>&#xA0;<span class="n">i</span>&#xA0;<span class="ow">in</span>&#xA0;<span class="n">computeHW2</span><span class="p">(</span><span class="n">N</span><span class="o">/</span><span class="mi">2</span><span class="p">):</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">yield</span>&#xA0;<span class="n">i</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">for</span>&#xA0;<span class="n">i</span>&#xA0;<span class="ow">in</span>&#xA0;<span class="n">computeHW2</span><span class="p">(</span><span class="n">N</span><span class="o">/</span><span class="mi">2</span><span class="p">):</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">yield</span>&#xA0;<span class="mi">2</span>&#xA0;<span class="o">*</span>&#xA0;<span class="n">i</span>
<br /></tt></blockquote><p>Talking more with Questioner, it turns out he didn't want the sequence, he wanted to be able 
    to randomly access elements of his list.  
    We can turn this function into a closed-form solution that computes the n'th element of this
    list:</p><blockquote class="code"><tt><span class="k">def</span>&#xA0;<span class="nf">closedHW</span><span class="p">(</span><span class="n">N</span><span class="p">):</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">if</span>&#xA0;<span class="n">N</span>&#xA0;<span class="o">==</span>&#xA0;<span class="mi">0</span><span class="p">:</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">return</span>&#xA0;<span class="mi">1</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">else</span><span class="p">:</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">bits</span>&#xA0;<span class="o">=</span>&#xA0;<span class="n">N</span><span class="o">.</span><span class="n">bit_length</span><span class="p">()</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">return</span>&#xA0;<span class="mi">2</span>&#xA0;<span class="o">*</span>&#xA0;<span class="n">closedHW</span><span class="p">(</span><span class="n">N</span>&#xA0;<span class="o">-</span>&#xA0;<span class="mi">2</span><span class="o">**</span><span class="p">(</span><span class="n">bits</span><span class="o">-</span><span class="mi">1</span><span class="p">))</span>
<br /></tt></blockquote><p>This function is still recursive, and so will use up to 30 stack frames for numbers up to 2**30,
    but doesn't allocate any lists at all.  This function is also in a simple tail-call form,
    so we can easily make it iterative:</p><blockquote class="code"><tt><span class="k">def</span>&#xA0;<span class="nf">closedHW_iterative</span><span class="p">(</span><span class="n">N</span><span class="p">):</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">hw</span>&#xA0;<span class="o">=</span>&#xA0;<span class="mi">1</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">while</span>&#xA0;<span class="n">N</span><span class="p">:</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">bits</span>&#xA0;<span class="o">=</span>&#xA0;<span class="n">N</span><span class="o">.</span><span class="n">bit_length</span><span class="p">()</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">N</span>&#xA0;<span class="o">-=</span>&#xA0;<span class="mi">2</span><span class="o">**</span><span class="p">(</span><span class="n">bits</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;<span class="n">hw</span>&#xA0;<span class="o">*=</span>&#xA0;<span class="mi">2</span>
<br />&#xA0;&#xA0;&#xA0;&#xA0;<span class="k">return</span>&#xA0;<span class="n">hw</span>
<br /></tt></blockquote><p>BTW, this code gets to use one of the few methods on integers, bit_length(), which is new in 2.7.</p><p>In the end, we eliminated the recursion, but not for any of the reasons Naysayer was darkly hinting at.</p><p>When people say Python is bad at recursion, they are referring to the fact that the stack can't
    grow beyond 1000 frames.  This makes it bad at the kind of 
    recursion that languages like Scheme and Haskell encourage. This school of thought uses recursive procedures
    for iterative processes, to put it in terms from 
    <a class="offsite" href="http://mitpress.mit.edu/sicp/">Structure and Interpretation of Computer Programs</a>.
    Python is not good for this sort of recursion, because it won't work for more than 1000 iterations,
    which is far too low a limit.</p><p>But truly recursive processes don't often need that much stack, so using recursive procedures for
    recursive processes is fine in Python.  Blanket statemtents like "recursion is almost always bad new in Python"
    are just simplistic.</p>]]></description>
    <link><![CDATA[http://nedbatchelder.com/blog/201205/recursive_dogma.html]]></link>
    <pubDate>2012-05-28 14:52:29</pubDate>
  </item>
  <item>
    <title><![CDATA[Anatoly Techtonik: Spyder IDE Internals: Highlighting in 2.2.0dev]]></title>
    <description><![CDATA[<b>UPD:</b>&nbsp;Highligher support in code editor have been improved, so its instance can now be traced easily.<br /><br />The entrypoint to syntax highlighting in Spyder IDE is located in CodeEditor widget at&nbsp;<a href="http://code.google.com/p/spyderlib/source/browse/spyderlib/widgets/sourcecode/codeeditor.py?r=b48946b15f99a4845aa44a8ff85204b3c60b8a93#452">spyderlib/widgets/sourcecode/codeeditor.py</a><br /><br />CodeEditor widget is basically file content in one of main tabs. The whole stack of tabs is called EditorStack. So editors are grouped in editor stacks, each editor renders one file, and each editor has its own highligher created from assigned self.highlighter_class<br /><br />Highlighers are implemented with Qt's <a href="http://www.pyside.org/docs/pyside/PySide/QtGui/QSyntaxHighlighter.html">QSyntaxHighlighter</a>. No pygments, nothing like this, so can't say if Qt is faster, but it should be.&nbsp;Default self.highligher_class for every code editor is&nbsp;<a href="http://code.google.com/p/spyderlib/source/browse/spyderlib/widgets/sourcecode/syntaxhighlighters.py?r=c037ef100bde3774939efd18192205a345345b76#227">TextSH</a>. The actual instance is created by set_language() method called from setup_editor(). If setup_editor() is not called, the highlighter can be unset, but frankly I don't know what's the purpose of using such editor.<br /><br />if set, syntax highlighter (self.highlighter) <b>is responsible</b> for:<br /><ul><li>coloring raw text data inside editor on load</li><li>coloring text data when editor is cloned</li><li>updating document highlight on line edits</li><li>providing color palette (scheme) for the editor</li><li>providing data for Outliner</li></ul>self.highlighter is <b>not</b> responsible for:<br /><ul><li>background highlight for current line</li><li>background highlight for search / current line occurrences</li></ul><br /><div>Enjoy hacking.</div><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/1623059707500976008-2954733978013825964?l=techtonik.rainforce.org" alt="" /></div>]]></description>
    <link><![CDATA[http://techtonik.rainforce.org/2012/05/spyder-ide-internals-highlighting-in.html]]></link>
    <pubDate>2012-05-28 04:11:50</pubDate>
  </item>
  <item>
    <title><![CDATA[Peter Hoffmann: Python markdown with github flavored code blocks]]></title>
    <description><![CDATA[<p>Fenced code blocks are a github extension to markdown:</p>

<pre><code>```python
print &quot;hello world&quot;
```
</code></pre>

<p>will render as:</p>

<pre><code>&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;
print &quot;hello world&quot;
&lt;/code&gt;&lt;/pre&gt;
</code></pre>

<p>The advantages are that you don't have to indent the code (which is useful when 
you copy and paste python code) and that you can add a language identifier which
can be used to highlight the code with tools like <a href="http://softwaremaniacs.org/soft/highlight/en/">highlight.js</a>. </p>

<p>Adding <a href="http://github.github.com/github-flavored-markdown/">github flavored markdown code blocks</a> to <a href="http://freewisdom.org/projects/python-markdown/">python markdown</a> is
really easy. There is already the <a href="http://freewisdom.org/projects/python-markdown/Fenced_Code_Blocks">fenced code blocks</a> extension. All you
have to do is to customize the regular expression in
<code>markdown/extensions/fenced_code.py</code>: </p>

<pre><code>67c67
&lt;     r'(?P&lt;fence&gt;^~{3,})[ ]*(\{?\.(?P&lt;lang&gt;[a-zA-Z0-9_-]*)\}?)?[ ]*\n(?P&lt;code&gt;.*?)(?P=fence)[ ]*$', 
---
&gt;     r'(?P&lt;fence&gt;^`{3,})[ ]*(?P&lt;lang&gt;[a-zA-Z0-9_-]*)[ ]*\n(?P&lt;code&gt;.*?)(?P=fence)[ ]*$', 
</code></pre>]]></description>
    <link><![CDATA[http://peter-hoffmann.com/2012/python-markdown-github-flavored-code-blocks.html]]></link>
    <pubDate>2012-05-28 00:00:00</pubDate>
  </item>
  <item>
    <title><![CDATA[A. Jesse Jiryu Davis: Python’s Thread Locals Are Weird]]></title>
    <description><![CDATA[<h1>The Weirdness</h1>
<p>What do you think this script prints?:</p>
<div class="codecolorer-container python default"><div class="python codecolorer"><span>import</span> <span>thread</span><span>,</span> <span>threading</span><span>,</span> <span>sys</span><br />
<br />
<span>class</span> Weeper<span>&#40;</span><span>object</span><span>&#41;</span>:<br />
&nbsp; &nbsp; <span>def</span> <span>__del__</span><span>&#40;</span><span>self</span><span>&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span>sys</span>.<span>stdout</span>.<span>write</span><span>&#40;</span><span>'oh cruel world %s<span>\n</span>'</span> % <span>thread</span>.<span>get_ident</span><span>&#40;</span><span>&#41;</span><span>&#41;</span><br />
<br />
local <span>=</span> <span>threading</span>.<span>local</span><span>&#40;</span><span>&#41;</span><br />
<br />
<span>def</span> target<span>&#40;</span><span>&#41;</span>:<br />
&nbsp; &nbsp; local.<span>weeper</span> <span>=</span> Weeper<span>&#40;</span><span>&#41;</span><br />
<br />
t <span>=</span> <span>threading</span>.<span>Thread</span><span>&#40;</span>target<span>=</span>target<span>&#41;</span><br />
t.<span>start</span><span>&#40;</span><span>&#41;</span><br />
t.<span>join</span><span>&#40;</span><span>&#41;</span><br />
<span>sys</span>.<span>stdout</span>.<span>write</span><span>&#40;</span><span>'done %s<span>\n</span>'</span> % <span>thread</span>.<span>get_ident</span><span>&#40;</span><span>&#41;</span><span>&#41;</span><br />
<span>getattr</span><span>&#40;</span>local<span>,</span> <span>'whatever'</span><span>,</span> <span>None</span><span>&#41;</span></div></div>
<p>If you guessed something like this:</p>
<div class="codecolorer-container text default"><div class="text codecolorer">oh cruel world 4475731968<br />
done 140735297751392</div></div>
<p>&#8230;then you&#8217;d be right, <em>in Python 2.7 and 3.x</em>. In Python 2.6 and older, the order of messages is reversed:</p>
<div class="codecolorer-container text default"><div class="text codecolorer">done 140735297751392<br />
oh cruel world 140735297751392</div></div>
<p>In New Python, the Weeper is deleted as soon as its thread dies, and __del__ runs on the dying thread. In Old Python, the Weeper isn&#8217;t deleted until the thread is dead <strong>and</strong> a different thread accesses the local&#8217;s __dict__. Thus the Weeper is deleted at the line <code class="codecolorer python default"><span class="python"><span>getattr</span><span>&#40;</span>local<span>,</span> <span>'whatever'</span><span>,</span> <span>None</span><span>&#41;</span></span></code>, after the thread dies, and Weeper.__del__ runs on the main thread.</p>
<p>What if we remove the <code class="codecolorer text default"><span class="text">getattr</span></code> call? In Old Python, this happens:</p>
<div class="codecolorer-container text default"><div class="text codecolorer">done 140735297751392<br />
Exception AttributeError: &quot;'NoneType' object has no attribute 'get_ident'&quot;<br />
&nbsp; &nbsp; in &lt;bound method Weeper.__del__ of &lt;__main__.Weeper object at 0x104f95590&gt;&gt;<br />
&nbsp; &nbsp; ignored</div></div>
<p>Without <code class="codecolorer text default"><span class="text">getattr</span></code>, the Weeper isn&#8217;t deleted until interpreter shutdown. The shutdown sequence is complex and hard to predict&mdash;in this case the <code class="codecolorer text default"><span class="text">thread</span></code> module has been set to <code class="codecolorer text default"><span class="text">None</span></code> before the Weeper is deleted, so Weeper.__del__ can&#8217;t do <code class="codecolorer python default"><span class="python"><span>thread</span>.<span>get_ident</span><span>&#40;</span><span>&#41;</span></span></code>.</p>
<h1>Thread Locals in Old Python</h1>
<p>To understand why locals act this way in Python 2.6 and older, let&#8217;s look at the implementation in C. The core interpreter&#8217;s <code class="codecolorer text default"><span class="text">PyThreadState</span></code> struct has a <code class="codecolorer text default"><span class="text">dict</span></code> attribute, and each <code class="codecolorer text default"><span class="text">threading.local</span></code> object has a <code class="codecolorer text default"><span class="text">key</span></code> attribute formatted like <code class="codecolorer text default"><span class="text">&quot;thread.local.&amp;lt;memory address of self&amp;gt;&quot;</span></code>. Each local has a <code class="codecolorer text default"><span class="text">__dict__</span></code> of attributes per thread, stored in <code class="codecolorer text default"><span class="text">PyThreadState</span></code>&#8216;s <code class="codecolorer text default"><span class="text">dict</span></code> with the local&#8217;s key.</p>
<p>threadmodule.c includes a function <code class="codecolorer text default"><span class="text">_ldict(localobject *self)</span></code> which takes a local and finds its <code class="codecolorer text default"><span class="text">__dict__</span></code> for the current thread. <code class="codecolorer text default"><span class="text">_ldict()</span></code>finds and returns the local&#8217;s <code class="codecolorer text default"><span class="text">__dict__</span></code> for this thread, <strong>and</strong> stores it in <code class="codecolorer text default"><span class="text">self-&gt;dict</span></code>.</p>
<p><img src="http://emptysquare.net/blog/wp-content/uploads/2012/05/old-python-thread-local-architecture.png" alt="Old Python's thread-local architecture" title="old-python-thread-local-architecture.png" border="0" width="461" height="337" /></p>
<p>This architecture has, in my opinion, a bug. Here&#8217;s the implementation of <code class="codecolorer text default"><span class="text">_ldict()</span></code>:</p>
<div class="codecolorer-container c default"><div class="c codecolorer"><span>static</span> PyObject <span>*</span> _ldict<span>&#40;</span>localobject <span>*</span>self<span>&#41;</span><br />
<span>&#123;</span><br />
&nbsp; &nbsp; PyObject <span>*</span>tdict <span>=</span> PyThreadState_GetDict<span>&#40;</span><span>&#41;</span><span>;</span> <span>// get PyThreadState-&gt;dict for this thread</span><br />
&nbsp; &nbsp; PyObject <span>*</span>ldict <span>=</span> PyDict_GetItem<span>&#40;</span>tdict<span>,</span> self<span>-&gt;</span>key<span>&#41;</span><span>;</span><br />
&nbsp; &nbsp; <span>if</span> <span>&#40;</span>ldict <span>==</span> NULL<span>&#41;</span> <span>&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ldict <span>=</span> PyDict_New<span>&#40;</span><span>&#41;</span><span>;</span> <span>/* we own ldict */</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; PyDict_SetItem<span>&#40;</span>tdict<span>,</span> self<span>-&gt;</span>key<span>,</span> ldict<span>&#41;</span><span>;</span><br />
<span>&nbsp; &nbsp; &nbsp; &nbsp; Py_CLEAR<span>&#40;</span>self<span>-&gt;</span>dict<span>&#41;</span><span>;</span><br /></span>&nbsp; &nbsp; &nbsp; &nbsp; Py_INCREF<span>&#40;</span>ldict<span>&#41;</span><span>;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; self<span>-&gt;</span>dict <span>=</span> ldict<span>;</span> <span>/* still borrowed */</span><br />
<br />
<span>&nbsp; &nbsp; &nbsp; &nbsp; <span>if</span> <span>&#40;</span>Py_TYPE<span>&#40;</span>self<span>&#41;</span><span>-&gt;</span>tp_init <span>!=</span> PyBaseObject_Type.<span>tp_init</span><span>&#41;</span> <span>&#123;</span><br /></span><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Py_TYPE<span>&#40;</span>self<span>&#41;</span><span>-&gt;</span>tp_init<span>&#40;</span><span>&#40;</span>PyObject<span>*</span><span>&#41;</span>self<span>,</span> self<span>-&gt;</span>args<span>,</span> self<span>-&gt;</span>kw<span>&#41;</span><span>;</span><br /></span>&nbsp; &nbsp; &nbsp; &nbsp; <span>&#125;</span><br />
&nbsp; &nbsp; <span>&#125;</span><br />
<br />
&nbsp; &nbsp; <span>/* The call to tp_init above may have caused another thread to run.</span><br />
<span>&nbsp; &nbsp; &nbsp; &nbsp;Install our ldict again. */</span><br />
&nbsp; &nbsp; <span>if</span> <span>&#40;</span>self<span>-&gt;</span>dict <span>!=</span> ldict<span>&#41;</span> <span>&#123;</span><br />
<span>&nbsp; &nbsp; &nbsp; &nbsp; Py_CLEAR<span>&#40;</span>self<span>-&gt;</span>dict<span>&#41;</span><span>;</span><br /></span>&nbsp; &nbsp; &nbsp; &nbsp; Py_INCREF<span>&#40;</span>ldict<span>&#41;</span><span>;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; self<span>-&gt;</span>dict <span>=</span> ldict<span>;</span><br />
&nbsp; &nbsp; <span>&#125;</span><br />
<br />
&nbsp; &nbsp; <span>return</span> ldict<span>;</span><br />
<span>&#125;</span></div></div>
<p>I&#8217;ve edited for brevity. There&#8217;s a few interesting things here&mdash;one is the check for a custom <code class="codecolorer text default"><span class="text">__init__</span></code> method. If this object is a subclass of local which overrides <code class="codecolorer text default"><span class="text">__init__</span></code>, then <code class="codecolorer text default"><span class="text">__init__</span></code> is called whenever a new thread accesses this local&#8217;s attributes for the first time.</p>
<p>But the main thing I&#8217;m showing you is the two calls to <code class="codecolorer text default"><span class="text">Py_CLEAR(self-&gt;dict)</span></code>, which decrements <code class="codecolorer text default"><span class="text">self-&gt;dict</span></code>&#8216;s refcount. It&#8217;s called when a thread accesses this local&#8217;s attributes for the first time, <strong>or</strong> if this thread is accessing the local&#8217;s attributes after a different thread has accessed them&mdash;that is, if <code class="codecolorer c default"><span class="c">self<span>-&gt;</span>dict <span>!=</span> ldict</span></code>.</p>
<p>So now we clearly understand why a thread&#8217;s locals aren&#8217;t deleted immediately after it dies:</p>
<ol>
<li>The worker thread stores a Weeper in <code class="codecolorer text default"><span class="text">local.weeper</span></code>. <code class="codecolorer text default"><span class="text">_ldict()</span></code> creates a new <code class="codecolorer text default"><span class="text">__dict__</span></code> for this thread and stores it as a value in <code class="codecolorer text default"><span class="text">PyThreadState-&gt;dict</span></code>, <strong>and</strong> stores it in <code class="codecolorer text default"><span class="text">local-&gt;dict</span></code>. So there are two references to this thread&#8217;s <code class="codecolorer text default"><span class="text">__dict__</span></code>: one from <code class="codecolorer text default"><span class="text">PyThreadState</span></code>, one from local.</li>
<li>The worker thread dies, and the interpreter deletes its <code class="codecolorer text default"><span class="text">PyThreadState</span></code>. Now there&#8217;s one reference to the dead thread&#8217;s <code class="codecolorer text default"><span class="text">__dict__</span></code>: <code class="codecolorer text default"><span class="text">local-&gt;dict</span></code>.</li>
<li>Finally, we do <code class="codecolorer python default"><span class="python"><span>getattr</span><span>&#40;</span>local<span>,</span> <span>'whatever'</span><span>,</span> <span>None</span><span>&#41;</span></span></code> from the main thread. In <code class="codecolorer text default"><span class="text">_ldict()</span></code>, <code class="codecolorer c default"><span class="c">self<span>-&gt;</span>dict <span>!=</span> ldict</span></code>, so <code class="codecolorer text default"><span class="text">self-&gt;dict</span></code> is dereferenced and replaced with the main thread&#8217;s <code class="codecolorer text default"><span class="text">__dict__</span></code>. Now the dead thread&#8217;s <code class="codecolorer text default"><span class="text">__dict__</span></code> has finally been completely dereferenced, and the Weeper is deleted.</li>
</ol>
<p>The bug is that <code class="codecolorer text default"><span class="text">_ldict()</span></code> both returns the local&#8217;s <code class="codecolorer text default"><span class="text">__dict__</span></code> for the current thread, <strong>and</strong> stores a reference to it. This is why the <code class="codecolorer text default"><span class="text">__dict__</span></code> isn&#8217;t deleted as soon as its thread dies: there&#8217;s a useless but persistent reference to the <code class="codecolorer text default"><span class="text">__dict__</span></code> until another thread comes along and clears it.</p>
<h1>Thread Locals in New Python</h1>
<p>In Python 2.7 and 3.x, the architecture&#8217;s a little more complex. Each <code class="codecolorer text default"><span class="text">PyThreadState</span></code>&#8216;s dict contains a dummy for each local, and each local holds a dict mapping weak references of dummies to a per-thread <code class="codecolorer text default"><span class="text">__dict__</span></code>.</p>
<p><img src="http://emptysquare.net/blog/wp-content/uploads/2012/05/new-python-thread-local-architecture.png" alt="New Python's thread-local architecture" title="new-python-thread-local-architecture.png" border="0" width="571" height="526" /></p>
<p>When a thread is dying and its <code class="codecolorer text default"><span class="text">PyThreadState</span></code> is deleted, weakref callbacks fire immediately on that thread, removing the thread&#8217;s <code class="codecolorer text default"><span class="text">__dict__</span></code> for each local. Conversely, when a local is deleted, it removes its dummy from <code class="codecolorer text default"><span class="text">PyThreadState-&gt;dict</span></code>.</p>
<p><code class="codecolorer text default"><span class="text">_ldict()</span></code> in New Python acts more sanely than in Old Python. It finds the current thread&#8217;s dummy in the <code class="codecolorer text default"><span class="text">PyThreadState</span></code>, and gets the <code class="codecolorer text default"><span class="text">__dict__</span></code> for this thread from the dummy. But unlike in Old Python, it doesn&#8217;t store a extra reference to <code class="codecolorer text default"><span class="text">__dict__</span></code> anywhere. It simply returns it:</p>
<div class="codecolorer-container c default"><div class="c codecolorer"><span>static</span> PyObject <span>*</span> _ldict<span>&#40;</span>localobject <span>*</span>self<span>&#41;</span><br />
<span>&#123;</span><br />
&nbsp; &nbsp; PyObject <span>*</span>tdict<span>,</span> <span>*</span>ldict<span>,</span> <span>*</span>dummy<span>;</span><br />
&nbsp; &nbsp; tdict <span>=</span> PyThreadState_GetDict<span>&#40;</span><span>&#41;</span><span>;</span><br />
&nbsp; &nbsp; dummy <span>=</span> PyDict_GetItem<span>&#40;</span>tdict<span>,</span> self<span>-&gt;</span>key<span>&#41;</span><span>;</span><br />
&nbsp; &nbsp; <span>if</span> <span>&#40;</span>dummy <span>==</span> NULL<span>&#41;</span> <span>&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ldict <span>=</span> _local_create_dummy<span>&#40;</span>self<span>&#41;</span><span>;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span>if</span> <span>&#40;</span>Py_TYPE<span>&#40;</span>self<span>&#41;</span><span>-&gt;</span>tp_init <span>!=</span> PyBaseObject_Type.<span>tp_init</span><span>&#41;</span> <span>&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Py_TYPE<span>&#40;</span>self<span>&#41;</span><span>-&gt;</span>tp_init<span>&#40;</span><span>&#40;</span>PyObject<span>*</span><span>&#41;</span>self<span>,</span> self<span>-&gt;</span>args<span>,</span> self<span>-&gt;</span>kw<span>&#41;</span><span>;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span>&#125;</span><br />
&nbsp; &nbsp; <span>&#125;</span> <span>else</span> <span>&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ldict <span>=</span> <span>&#40;</span><span>&#40;</span>localdummyobject <span>*</span><span>&#41;</span> dummy<span>&#41;</span><span>-&gt;</span>localdict<span>;</span><br />
&nbsp; &nbsp; <span>&#125;</span><br />
<br />
&nbsp; &nbsp; <span>return</span> ldict<span>;</span><br />
<span>&#125;</span></div></div>
<p>This whole weakrefs-to-dummies technique is, apparently, intended to deal with some cyclic garbage collection problem I don&#8217;t understand very well. I believe the real reason why Python 2.7 acts as expected when executing my script, and why Python 2.6 acts weird, is that 2.6 stores the extra useless reference to the <code class="codecolorer text default"><span class="text">__dict__</span></code> and 2.7 does not.</p>]]></description>
    <link><![CDATA[http://emptysquare.net/blog/pythons-thread-locals-are-weird/?utm_source=rss&utm_medium=rss&utm_campaign=pythons-thread-locals-are-weird]]></link>
    <pubDate>2012-05-27 20:46:58</pubDate>
  </item>
  <item>
    <title><![CDATA[Juho Vepsäläinen: Thoughts on Kasvu Open Forum and Djangocon Finland 2012]]></title>
    <description><![CDATA[Two days, two conferences. The first was a local, business oriented one, <a href="http://www.kasvuopen.fi/paivamaarat/kasvu-open-forum-25-5/">Kasvu Open Forum</a>. The second, <a href="http://djangocon.fi/">Djangocon Finland 2012</a>, focused mainly on technology. I gave two talks in the latter one. It was very nice to experience both events and meet some new people and a few old acquaintances.<br /><h2><br /></h2><h2> Kasvu Open Forum</h2><div><a href="http://kasvuopen.fi/">Kasvu Open</a> is a competition of sorts aimed for Finnish growth ventures. This is the second year they are organizing it so things are just about to get rolling. They have two series, one for ideas and one for established companies. Me and my business partner participated in the former one this year with an entry.<br /><br />We didn't make it to the finals and weren't impressed by the quality of the feedback given. This event totally made up for it. This is definitely something they can improve on the next year. The last thing you want to do is to discourage some potential idea or company. After all Kasvu Open is in the business of creating new business.</div><div><br /></div><div>You might expect business conferences such as this to be really boring. This wasn't the case here. Each talk given gave some unique view to growth venturing. For instance it was particularly interesting to see how different the mindsets of a venture capitalist and a business angel can be. Former focuses on profit while the latter thinks in more long term and uses a different kind of investment strategy.</div><div><br /></div><div>I also enjoyed the talk of Jouni Hynynen. He represented <a href="http://www.keksintosaatio.fi/en/Home/">The Foundation of Finnish Inventions</a> and explained how <a href="http://nixtu.blogspot.com/2011/12/brief-primer-to-immaterial-rights.html">immaterial rights</a> relate to business and what is their worth in practice. Even though I'm somewhat categorically opposed to concepts such as software patents, the talk gave some nice insight to the subject.</div><div><br /></div><div>Overall it seems like there is some positive buzz going on in the Jyväskylä area. It might not be the Silicon Valley and we might be missing the scale benefits. I wouldn't be surprised if something really interesting emerged from the area within the next decades.<br /><br /></div><h2> Djangocon Finland 2012</h2><div>This was the first time I visited the Finnish version of <a href="http://djangocon.fi/">Djangocon</a>. I think there were around&nbsp;forty&nbsp;people or so participating the event. The talks were primarily technically oriented. There were a couple of longer talks and several lightning talks.</div><div><br /></div><div>I actually met a reader of this blog (apparently there are those) at the conference. That was quite a pleasant surprise to be honest. It's small things such as this that make it all worth it.<br /><br /><h3>Thoughts on "Kaleva.fi - how we replaced 10 years of legacy code in one year"</h3>It was particularly interesting to see what Kaleva.fi looks like from "outside" in terms of <a href="http://en.wikipedia.org/wiki/DevOps">DevOps</a>. I participated in the project as a software designer during the past year for a period of a few months. So I got to know certain bits of it quite well. I never really looked into the overall infrastructure (too busy staring at my code :) ), though.<br /><br />There were many interesting tidbits in Markus' talk. Especially the bits on scaling the service were interesting. It's quite different to develop a service used by hundreds of thousands than something that has only a few users. You get a lot of new problems to solve.<br /><br /><h3>Thoughts on other talks</h3><div>There was this one guy that made Django act like PHP. <a href="https://github.com/mjtorn/dhp">Django Home Pages</a> is a terrible abomination that simply should not exist. I guess that was kind of the point, though. He created it just in order to see if it can be done.</div><div><br /></div><div>Leo Honkanen discussed about classy Django applications. I think the main gist here was that with some effort you can provide namespaced url lookups for your templates. Essentially you have to deal with routing using a proxy class that implements urls using a property. The proxy class contains the name of the namespace as a class level attribute. I believe it is possible to implement this as a class method so you can avoid instantiating the whole thing at your url definition.</div><div><br /></div><div>I'm not entirely sure if one should abuse classes this way. There might be a neater functional solution around to be found. If I ever need to namespace my urls somehow, I'll keep this in mind.</div><div><br /></div><div>There were a couple of lightning talks as well. The <a href="http://en.wikipedia.org/wiki/Behavior_Driven_Development">BDD</a> one was semi-interesting. I couldn't see myself writing that amount of code anytime soon, though. There must be some nicer way to describe stories.</div><div><br /></div><h3>bongaus.fi - Spotting Service Powered by Django</h3></div><div>My first talk had to do with a service me and my business partner developed during the Spring. We did the development of <a href="http://bongaus.fi/">bongaus.fi</a> in a few distinct phases. The idea of the talk was to give some insight how we created the service and what kind of lessons we learned while doing it. I hope the people got something out of it! You can examine the slides below (probably not visible in RSS):</div><div id="__ss_13090811"><strong><a href="http://www.slideshare.net/bebraw/bongausfi-spotting-service-powered-by-django" target="_blank" title="bongaus.fi - Spotting Service Powered by Django">bongaus.fi - Spotting Service Powered by Django</a></strong>  <br /><div>View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/bebraw" target="_blank">Juho Vepsäläinen</a></div></div><div>If there is something you should pick out from the talk I believe it is the importance of developing a <a href="http://en.wikipedia.org/wiki/Minimum_viable_product">Minimum Viable Product</a> (MVP). The only way to know if your product is on the right track is to give it for your users to test. Developing a MVP is an effective way to do this. Besides, it is really fast to get one done since you don't need to get stuck on the details.<br /><br />In development of bongaus.fi we noticed <a href="http://en.wikipedia.org/wiki/Pareto_principle">Pareto principle</a> applies quite well here. It takes only perhaps 20% or so time to get the relevant bits done. The rest is just tweaking and dealing the corner cases. And boy that sure can take time.<br /><br />Another important thing to pick out is the value of pivots. Even if you are doing something and going to a certain direction, doesn't mean you should be going there indefinitely. It can pay off to adjust the trajectory and try something perhaps a bit different. I believe the willingness to pivot is one of the key attributes of startups that become successful.<br /><br /><h3>Speccer</h3></div><div>My second, really brief talk, had to do with <a href="https://github.com/bebraw/speccer">Speccer</a>. It is a small testing tool I developed ages ago to make using <a href="http://docs.python.org/library/unittest.html">unittest</a> bearable. To quote myself "unittest provides testing for masochists while Speccer is meant for the rest of us". I hope the slides below give you the gist of it:</div><div id="__ss_13090828"><strong><a href="http://www.slideshare.net/bebraw/speccer" target="_blank" title="Speccer">Speccer</a></strong>  <br /><div>View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/bebraw" target="_blank">Juho Vepsäläinen</a> </div></div><div>Essentially the tool just transforms the light Pythonish syntax (you can mix Python with it) to code using unittest. This means you get to enjoy from the benefits of the both. You get the robust output provided by unittest's test runner while get to use a lighter syntax.<br /><br /></div><h2> Conclusion</h2><div>At times I feel like I'm slowly drifting away from a pure development role and more into business. These kind of conferences seem to confirm this. It takes a lot more than just technical skill to make things work in a real world.</div><div><br /></div><div>Overall it seems like a good idea to be active. You get a lot of new contacts that in turn might prove to be valuable longer term (applies both ways). In addition these sort of events give you a nice extra burst of motivation and helps you to validate some of the work you have done. Sometimes it is a good idea to step out of your role a bit and try something different (ie. a business conf :) ).</div><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/7507869444539635439-832664689343121859?l=nixtu.blogspot.com" alt="" /></div>]]></description>
    <link><![CDATA[http://nixtu.blogspot.com/2012/05/thoughts-on-kasvu-open-forum-and.html]]></link>
    <pubDate>2012-05-27 12:38:01</pubDate>
  </item>
  <item>
    <title><![CDATA[Go Deh: Python: Choice of the one obvious way to do it.]]></title>
    <description><![CDATA[I just worked on a new Rosetta Code <a href="http://rosettacode.org/wiki/Fibonacci_n-step_number_sequences">task</a>&nbsp;on Fibonacci-<i>like </i>sequences where the solution works by giving the initial conditions and being returned something that can then create members of the defined series. You create a series generator factory then use the series generator returned. (The above uses the word generator in its non programming specific sense).<br /><br /><h3><b>Currently we have <a href="http://rosettacode.org/wiki/Fibonacci_n-step_number_sequences#Python">three versions</a> of answers to the task in Python:</b></h3><br /><br /><br /><h3><span class="mw-headline" id="Python:_function_returning_a_function"><span>Python: function returning a function</span></span></h3><pre class="python highlighted_source"><span><span class="sy0">&gt;&gt;&gt;</span> <span class="kw1">def</span> fiblike<span class="br0">(</span>start<span class="br0">)</span>:<br /> addnum <span class="sy0">=</span> <span class="kw2">len</span><span class="br0">(</span>start<span class="br0">)</span><br /> memo <span class="sy0">=</span> start<span class="br0">[</span>:<span class="br0">]</span><br /> <span class="kw1">def</span> fibber<span class="br0">(</span>n<span class="br0">)</span>:<br />  <span class="kw1">try</span>:<br />   <span class="kw1">return</span> memo<span class="br0">[</span>n<span class="br0">]</span><br />  <span class="kw1">except</span> <span class="kw2">IndexError</span>:<br />   ans <span class="sy0">=</span> <span class="kw2">sum</span><span class="br0">(</span>fibber<span class="br0">(</span>i<span class="br0">)</span> <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span>n-addnum<span class="sy0">,</span> n<span class="br0">)</span><span class="br0">)</span><br />   memo.<span class="me1">append</span><span class="br0">(</span>ans<span class="br0">)</span><br />   <span class="kw1">return</span> ans<br /> <span class="kw1">return</span> fibber<br />&nbsp;<br /><span class="sy0">&gt;&gt;&gt;</span> fibo <span class="sy0">=</span> fiblike<span class="br0">(</span><span class="br0">[</span><span class="nu0">1</span><span class="sy0">,</span><span class="nu0">1</span><span class="br0">]</span><span class="br0">)</span><br /><span class="sy0">&gt;&gt;&gt;</span> <span class="br0">[</span>fibo<span class="br0">(</span>i<span class="br0">)</span> <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span><span class="nu0">10</span><span class="br0">)</span><span class="br0">]</span><br /><span class="br0">[</span><span class="nu0">1</span><span class="sy0">,</span> <span class="nu0">1</span><span class="sy0">,</span> <span class="nu0">2</span><span class="sy0">,</span> <span class="nu0">3</span><span class="sy0">,</span> <span class="nu0">5</span><span class="sy0">,</span> <span class="nu0">8</span><span class="sy0">,</span> <span class="nu0">13</span><span class="sy0">,</span> <span class="nu0">21</span><span class="sy0">,</span> <span class="nu0">34</span><span class="sy0">,</span> <span class="nu0">55</span><span class="br0">]</span><br /><span class="sy0">&gt;&gt;&gt;</span> lucas <span class="sy0">=</span> fiblike<span class="br0">(</span><span class="br0">[</span><span class="nu0">2</span><span class="sy0">,</span><span class="nu0">1</span><span class="br0">]</span><span class="br0">)</span><br /><span class="sy0">&gt;&gt;&gt;</span> <span class="br0">[</span>lucas<span class="br0">(</span>i<span class="br0">)</span> <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span><span class="nu0">10</span><span class="br0">)</span><span class="br0">]</span><br /><span class="br0">[</span><span class="nu0">2</span><span class="sy0">,</span> <span class="nu0">1</span><span class="sy0">,</span> <span class="nu0">3</span><span class="sy0">,</span> <span class="nu0">4</span><span class="sy0">,</span> <span class="nu0">7</span><span class="sy0">,</span> <span class="nu0">11</span><span class="sy0">,</span> <span class="nu0">18</span><span class="sy0">,</span> <span class="nu0">29</span><span class="sy0">,</span> <span class="nu0">47</span><span class="sy0">,</span> <span class="nu0">76</span><span class="br0">]</span><br /><span class="sy0">&gt;&gt;&gt;</span> <span class="kw1">for</span> n<span class="sy0">,</span> name <span class="kw1">in</span> <span class="kw2">zip</span><span class="br0">(</span><span class="kw2">range</span><span class="br0">(</span><span class="nu0">2</span><span class="sy0">,</span><span class="nu0">11</span><span class="br0">)</span><span class="sy0">,</span> <span class="st0">'fibo tribo tetra penta hexa hepta octo nona deca'</span>.<span class="me1">split</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span>&nbsp;:<br /> fibber <span class="sy0">=</span> fiblike<span class="br0">(</span><span class="br0">[</span><span class="nu0">1</span><span class="br0">]</span> + <span class="br0">[</span><span class="nu0">2</span>**i <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span>n-<span class="nu0">1</span><span class="br0">)</span><span class="br0">]</span><span class="br0">)</span><br /> <span class="kw1">print</span><span class="br0">(</span><span class="st0">'n=%2i,&nbsp;%5snacci -&gt;&nbsp;%s ...'</span>&nbsp;% <span class="br0">(</span>n<span class="sy0">,</span> name<span class="sy0">,</span> <span class="st0">' '</span>.<span class="me1">join</span><span class="br0">(</span><span class="kw2">str</span><span class="br0">(</span>fibber<span class="br0">(</span>i<span class="br0">)</span><span class="br0">)</span> <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span><span class="nu0">15</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><br />&nbsp;<br />&nbsp;<br />n<span class="sy0">=</span> <span class="nu0">2</span><span class="sy0">,</span>  fibonacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">3</span> <span class="nu0">5</span> <span class="nu0">8</span> <span class="nu0">13</span> <span class="nu0">21</span> <span class="nu0">34</span> <span class="nu0">55</span> <span class="nu0">89</span> <span class="nu0">144</span> <span class="nu0">233</span> <span class="nu0">377</span> <span class="nu0">610</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">3</span><span class="sy0">,</span> tribonacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">7</span> <span class="nu0">13</span> <span class="nu0">24</span> <span class="nu0">44</span> <span class="nu0">81</span> <span class="nu0">149</span> <span class="nu0">274</span> <span class="nu0">504</span> <span class="nu0">927</span> <span class="nu0">1705</span> <span class="nu0">3136</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">4</span><span class="sy0">,</span> tetranacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">15</span> <span class="nu0">29</span> <span class="nu0">56</span> <span class="nu0">108</span> <span class="nu0">208</span> <span class="nu0">401</span> <span class="nu0">773</span> <span class="nu0">1490</span> <span class="nu0">2872</span> <span class="nu0">5536</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">5</span><span class="sy0">,</span> pentanacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">31</span> <span class="nu0">61</span> <span class="nu0">120</span> <span class="nu0">236</span> <span class="nu0">464</span> <span class="nu0">912</span> <span class="nu0">1793</span> <span class="nu0">3525</span> <span class="nu0">6930</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">6</span><span class="sy0">,</span>  hexanacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">32</span> <span class="nu0">63</span> <span class="nu0">125</span> <span class="nu0">248</span> <span class="nu0">492</span> <span class="nu0">976</span> <span class="nu0">1936</span> <span class="nu0">3840</span> <span class="nu0">7617</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">7</span><span class="sy0">,</span> heptanacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">32</span> <span class="nu0">64</span> <span class="nu0">127</span> <span class="nu0">253</span> <span class="nu0">504</span> <span class="nu0">1004</span> <span class="nu0">2000</span> <span class="nu0">3984</span> <span class="nu0">7936</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">8</span><span class="sy0">,</span>  octonacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">32</span> <span class="nu0">64</span> <span class="nu0">128</span> <span class="nu0">255</span> <span class="nu0">509</span> <span class="nu0">1016</span> <span class="nu0">2028</span> <span class="nu0">4048</span> <span class="nu0">8080</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">9</span><span class="sy0">,</span>  nonanacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">32</span> <span class="nu0">64</span> <span class="nu0">128</span> <span class="nu0">256</span> <span class="nu0">511</span> <span class="nu0">1021</span> <span class="nu0">2040</span> <span class="nu0">4076</span> <span class="nu0">8144</span> ...<br /><span class="me1">n</span><span class="sy0">=</span><span class="nu0">10</span><span class="sy0">,</span>  decanacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">32</span> <span class="nu0">64</span> <span class="nu0">128</span> <span class="nu0">256</span> <span class="nu0">512</span> <span class="nu0">1023</span> <span class="nu0">2045</span> <span class="nu0">4088</span> <span class="nu0">8172</span> ...<br /><span class="sy0">&gt;&gt;&gt;</span> </span></pre><h3><span class="mw-headline" id="Python:_Callable_class"><span><br />Python: Callable class</span></span></h3><pre class="python highlighted_source"><span><span class="sy0">&gt;&gt;&gt;</span> <span class="kw1">class</span> Fiblike<span class="br0">(</span><span class="br0">)</span>:<br /> <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">(</span><span class="kw2">self</span><span class="sy0">,</span> start<span class="br0">)</span>:<br />  <span class="kw2">self</span>.<span class="me1">addnum</span> <span class="sy0">=</span> <span class="kw2">len</span><span class="br0">(</span>start<span class="br0">)</span><br />  <span class="kw2">self</span>.<span class="me1">memo</span> <span class="sy0">=</span> start<span class="br0">[</span>:<span class="br0">]</span><br /> <span class="kw1">def</span> <span class="kw4">__call__</span><span class="br0">(</span><span class="kw2">self</span><span class="sy0">,</span> n<span class="br0">)</span>:<br />  <span class="kw1">try</span>:<br />   <span class="kw1">return</span> <span class="kw2">self</span>.<span class="me1">memo</span><span class="br0">[</span>n<span class="br0">]</span><br />  <span class="kw1">except</span> <span class="kw2">IndexError</span>:<br />   ans <span class="sy0">=</span> <span class="kw2">sum</span><span class="br0">(</span><span class="kw2">self</span><span class="br0">(</span>i<span class="br0">)</span> <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span>n-<span class="kw2">self</span>.<span class="me1">addnum</span><span class="sy0">,</span> n<span class="br0">)</span><span class="br0">)</span><br />   <span class="kw2">self</span>.<span class="me1">memo</span>.<span class="me1">append</span><span class="br0">(</span>ans<span class="br0">)</span><br />   <span class="kw1">return</span> ans<br />&nbsp;<br />&nbsp;<br /><span class="sy0">&gt;&gt;&gt;</span> fibo <span class="sy0">=</span> Fiblike<span class="br0">(</span><span class="br0">[</span><span class="nu0">1</span><span class="sy0">,</span><span class="nu0">1</span><span class="br0">]</span><span class="br0">)</span><br /><span class="sy0">&gt;&gt;&gt;</span> <span class="br0">[</span>fibo<span class="br0">(</span>i<span class="br0">)</span> <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span><span class="nu0">10</span><span class="br0">)</span><span class="br0">]</span><br /><span class="br0">[</span><span class="nu0">1</span><span class="sy0">,</span> <span class="nu0">1</span><span class="sy0">,</span> <span class="nu0">2</span><span class="sy0">,</span> <span class="nu0">3</span><span class="sy0">,</span> <span class="nu0">5</span><span class="sy0">,</span> <span class="nu0">8</span><span class="sy0">,</span> <span class="nu0">13</span><span class="sy0">,</span> <span class="nu0">21</span><span class="sy0">,</span> <span class="nu0">34</span><span class="sy0">,</span> <span class="nu0">55</span><span class="br0">]</span><br /><span class="sy0">&gt;&gt;&gt;</span> lucas <span class="sy0">=</span> Fiblike<span class="br0">(</span><span class="br0">[</span><span class="nu0">2</span><span class="sy0">,</span><span class="nu0">1</span><span class="br0">]</span><span class="br0">)</span><br /><span class="sy0">&gt;&gt;&gt;</span> <span class="br0">[</span>lucas<span class="br0">(</span>i<span class="br0">)</span> <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span><span class="nu0">10</span><span class="br0">)</span><span class="br0">]</span><br /><span class="br0">[</span><span class="nu0">2</span><span class="sy0">,</span> <span class="nu0">1</span><span class="sy0">,</span> <span class="nu0">3</span><span class="sy0">,</span> <span class="nu0">4</span><span class="sy0">,</span> <span class="nu0">7</span><span class="sy0">,</span> <span class="nu0">11</span><span class="sy0">,</span> <span class="nu0">18</span><span class="sy0">,</span> <span class="nu0">29</span><span class="sy0">,</span> <span class="nu0">47</span><span class="sy0">,</span> <span class="nu0">76</span><span class="br0">]</span><br /><span class="sy0">&gt;&gt;&gt;</span> <span class="kw1">for</span> n<span class="sy0">,</span> name <span class="kw1">in</span> <span class="kw2">zip</span><span class="br0">(</span><span class="kw2">range</span><span class="br0">(</span><span class="nu0">2</span><span class="sy0">,</span><span class="nu0">11</span><span class="br0">)</span><span class="sy0">,</span> <span class="st0">'fibo tribo tetra penta hexa hepta octo nona deca'</span>.<span class="me1">split</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span>&nbsp;:<br /> fibber <span class="sy0">=</span> Fiblike<span class="br0">(</span><span class="br0">[</span><span class="nu0">1</span><span class="br0">]</span> + <span class="br0">[</span><span class="nu0">2</span>**i <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span>n-<span class="nu0">1</span><span class="br0">)</span><span class="br0">]</span><span class="br0">)</span><br /> <span class="kw1">print</span><span class="br0">(</span><span class="st0">'n=%2i,&nbsp;%5snacci -&gt;&nbsp;%s ...'</span>&nbsp;% <span class="br0">(</span>n<span class="sy0">,</span> name<span class="sy0">,</span> <span class="st0">' '</span>.<span class="me1">join</span><span class="br0">(</span><span class="kw2">str</span><span class="br0">(</span>fibber<span class="br0">(</span>i<span class="br0">)</span><span class="br0">)</span> <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">range</span><span class="br0">(</span><span class="nu0">15</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><br />&nbsp;<br />&nbsp;<br />n<span class="sy0">=</span> <span class="nu0">2</span><span class="sy0">,</span>  fibonacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">3</span> <span class="nu0">5</span> <span class="nu0">8</span> <span class="nu0">13</span> <span class="nu0">21</span> <span class="nu0">34</span> <span class="nu0">55</span> <span class="nu0">89</span> <span class="nu0">144</span> <span class="nu0">233</span> <span class="nu0">377</span> <span class="nu0">610</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">3</span><span class="sy0">,</span> tribonacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">7</span> <span class="nu0">13</span> <span class="nu0">24</span> <span class="nu0">44</span> <span class="nu0">81</span> <span class="nu0">149</span> <span class="nu0">274</span> <span class="nu0">504</span> <span class="nu0">927</span> <span class="nu0">1705</span> <span class="nu0">3136</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">4</span><span class="sy0">,</span> tetranacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">15</span> <span class="nu0">29</span> <span class="nu0">56</span> <span class="nu0">108</span> <span class="nu0">208</span> <span class="nu0">401</span> <span class="nu0">773</span> <span class="nu0">1490</span> <span class="nu0">2872</span> <span class="nu0">5536</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">5</span><span class="sy0">,</span> pentanacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">31</span> <span class="nu0">61</span> <span class="nu0">120</span> <span class="nu0">236</span> <span class="nu0">464</span> <span class="nu0">912</span> <span class="nu0">1793</span> <span class="nu0">3525</span> <span class="nu0">6930</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">6</span><span class="sy0">,</span>  hexanacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">32</span> <span class="nu0">63</span> <span class="nu0">125</span> <span class="nu0">248</span> <span class="nu0">492</span> <span class="nu0">976</span> <span class="nu0">1936</span> <span class="nu0">3840</span> <span class="nu0">7617</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">7</span><span class="sy0">,</span> heptanacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">32</span> <span class="nu0">64</span> <span class="nu0">127</span> <span class="nu0">253</span> <span class="nu0">504</span> <span class="nu0">1004</span> <span class="nu0">2000</span> <span class="nu0">3984</span> <span class="nu0">7936</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">8</span><span class="sy0">,</span>  octonacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">32</span> <span class="nu0">64</span> <span class="nu0">128</span> <span class="nu0">255</span> <span class="nu0">509</span> <span class="nu0">1016</span> <span class="nu0">2028</span> <span class="nu0">4048</span> <span class="nu0">8080</span> ...<br /><span class="me1">n</span><span class="sy0">=</span> <span class="nu0">9</span><span class="sy0">,</span>  nonanacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">32</span> <span class="nu0">64</span> <span class="nu0">128</span> <span class="nu0">256</span> <span class="nu0">511</span> <span class="nu0">1021</span> <span class="nu0">2040</span> <span class="nu0">4076</span> <span class="nu0">8144</span> ...<br /><span class="me1">n</span><span class="sy0">=</span><span class="nu0">10</span><span class="sy0">,</span>  decanacci -<span class="sy0">&gt;</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">4</span> <span class="nu0">8</span> <span class="nu0">16</span> <span class="nu0">32</span> <span class="nu0">64</span> <span class="nu0">128</span> <span class="nu0">256</span> <span class="nu0">512</span> <span class="nu0">1023</span> <span class="nu0">2045</span> <span class="nu0">4088</span> <span class="nu0">8172</span> ...<br /><span class="sy0">&gt;&gt;&gt;</span> </span></pre><h3><span class="mw-headline" id="Generator"><span><br />Generator</span></span></h3><pre class="python highlighted_source"><span><span class="kw1">from</span> <span class="kw3">itertools</span> <span class="kw1">import</span> islice<span class="sy0">,</span> cycle<br />&nbsp;<br /><span class="kw1">def</span> fiblike<span class="br0">(</span>tail<span class="br0">)</span>:<br />    <span class="kw1">for</span> x <span class="kw1">in</span> tail:<br />        <span class="kw1">yield</span> x<br />    <span class="kw1">for</span> i <span class="kw1">in</span> cycle<span class="br0">(</span><span class="kw2">xrange</span><span class="br0">(</span><span class="kw2">len</span><span class="br0">(</span>tail<span class="br0">)</span><span class="br0">)</span><span class="br0">)</span>:<br />        tail<span class="br0">[</span>i<span class="br0">]</span> <span class="sy0">=</span> x <span class="sy0">=</span> <span class="kw2">sum</span><span class="br0">(</span>tail<span class="br0">)</span><br />        <span class="kw1">yield</span> x<br />&nbsp;<br />fibo <span class="sy0">=</span> fiblike<span class="br0">(</span><span class="br0">[</span><span class="nu0">1</span><span class="sy0">,</span> <span class="nu0">1</span><span class="br0">]</span><span class="br0">)</span><br /><span class="kw1">print</span> <span class="kw2">list</span><span class="br0">(</span>islice<span class="br0">(</span>fibo<span class="sy0">,</span> <span class="nu0">10</span><span class="br0">)</span><span class="br0">)</span><br />lucas <span class="sy0">=</span> fiblike<span class="br0">(</span><span class="br0">[</span><span class="nu0">2</span><span class="sy0">,</span> <span class="nu0">1</span><span class="br0">]</span><span class="br0">)</span><br /><span class="kw1">print</span> <span class="kw2">list</span><span class="br0">(</span>islice<span class="br0">(</span>lucas<span class="sy0">,</span> <span class="nu0">10</span><span class="br0">)</span><span class="br0">)</span><br />&nbsp;<br />suffixes <span class="sy0">=</span> <span class="st0">"fibo tribo tetra penta hexa hepta octo nona deca"</span><br /><span class="kw1">for</span> n<span class="sy0">,</span> name <span class="kw1">in</span> <span class="kw2">zip</span><span class="br0">(</span><span class="kw2">xrange</span><span class="br0">(</span><span class="nu0">2</span><span class="sy0">,</span> <span class="nu0">11</span><span class="br0">)</span><span class="sy0">,</span> suffixes.<span class="me1">split</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span>:<br />    fib <span class="sy0">=</span> fiblike<span class="br0">(</span><span class="br0">[</span><span class="nu0">1</span><span class="br0">]</span> + <span class="br0">[</span><span class="nu0">2</span> ** i <span class="kw1">for</span> i <span class="kw1">in</span> <span class="kw2">xrange</span><span class="br0">(</span>n - <span class="nu0">1</span><span class="br0">)</span><span class="br0">]</span><span class="br0">)</span><br />    items <span class="sy0">=</span> <span class="kw2">list</span><span class="br0">(</span>islice<span class="br0">(</span>fib<span class="sy0">,</span> <span class="nu0">15</span><span class="br0">)</span><span class="br0">)</span><br />    <span class="kw1">print</span> <span class="st0">"n=%2i,&nbsp;%5snacci -&gt;&nbsp;%s ..."</span>&nbsp;% <span class="br0">(</span>n<span class="sy0">,</span> name<span class="sy0">,</span> items<span class="br0">)</span></span></pre><div> <dl><dt><span>Output:</span></dt></dl></div><pre><span>[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]<br />[2, 1, 3, 4, 7, 11, 18, 29, 47, 76]<br />n= 2,  fibonacci -&gt; [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610] ...<br />n= 3, tribonacci -&gt; [1, 1, 2, 4, 7, 13, 24, 44, 81, 149, 274, 504, 927, 1705, 3136] ...<br />n= 4, tetranacci -&gt; [1, 1, 2, 4, 8, 15, 29, 56, 108, 208, 401, 773, 1490, 2872, 5536] ...<br />n= 5, pentanacci -&gt; [1, 1, 2, 4, 8, 16, 31, 61, 120, 236, 464, 912, 1793, 3525, 6930] ...<br />n= 6,  hexanacci -&gt; [1, 1, 2, 4, 8, 16, 32, 63, 125, 248, 492, 976, 1936, 3840, 7617] ...<br />n= 7, heptanacci -&gt; [1, 1, 2, 4, 8, 16, 32, 64, 127, 253, 504, 1004, 2000, 3984, 7936] ...<br />n= 8,  octonacci -&gt; [1, 1, 2, 4, 8, 16, 32, 64, 128, 255, 509, 1016, 2028, 4048, 8080] ...<br />n= 9,  nonanacci -&gt; [1, 1, 2, 4, 8, 16, 32, 64, 128, 256, 511, 1021, 2040, 4076, 8144] ...<br />n=10,  decanacci -&gt; [1, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1023, 2045, 4088, 8172] ...</span></pre><br /><br /><h3><b>Three answers and Zen</b></h3>So how does the existence of three ways of giving an answer square with that part of the <a href="http://www.python.org/dev/peps/pep-0020/">Zen of Python</a> which states:<br /><span>&nbsp; &nbsp;&nbsp;There should be one-- <i>and preferably only one</i> --obvious way to do it.</span><br /><br />This comes down to a matter of style. Python supports many <a href="http://docs.python.org/howto/functional.html#introduction">programming styles</a>, (often called programming&nbsp;paradigms). What example might best fit a situation should depend on the surrounding programming style in use. The function calling a function, callable class, and generator solutions might best fit situations where it is to fit within programs using the&nbsp;procedural, object-oriented and functional styles respectively.<br /><br /><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/11149365-8044632841752546307?l=paddy3118.blogspot.com" alt="" /></div><img src="http://feeds.feedburner.com/~r/GoDeh/~4/gm16jPJryrk" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/GoDeh/~3/gm16jPJryrk/python-choice-of-one-obvious-way-to-do.html]]></link>
    <pubDate>2012-05-27 08:01:35</pubDate>
  </item>
  <item>
    <title><![CDATA[Twisted Matrix Labs: Twisted 12.1.0pre1]]></title>
    <description><![CDATA[Thanks to the efforts of Thomas Hervé, Twisted 12.1.0pre1 pre-release is now available for testing.You can find the tarballs here:<br />
<blockquote class="tr_bq">
<a href="http://people.canonical.com/~therve/Twisted/12.1.0pre1/">http://people.canonical.com/~therve/Twisted/12.1.0pre1/</a></blockquote>
Among the 106 tickets closed since our last release, you can find:<br />
<br />
<ul>
<li>The revival of the kqueue reactor for BSD platforms.</li>
<li>epoll is now the default reactor under Linux after a fix to handle
files on stdin/stdout.</li>
<li>New reactors supporting GTK3 and GObject-Introspection.</li>
<li>Several enhancements regarding file descriptors passing: systemd
support for servers, ability to send and receive file descriptors across Unix sockets, and an AMP argument using that feature.</li>
<li>Support for IPv6 literals in connectTCP.</li>
<li>Persistent connections support for the new HTTP client.</li>
</ul>
This will be the last release
supporting Python 2.5.

Please give it a round of tests to help make a great release!<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/1267458971896358542-8950901374440584676?l=labs.twistedmatrix.com" alt="" /></div><img src="http://feeds.feedburner.com/~r/TwistedMatrixLaboratories/~4/0I8HEmesDcs" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/TwistedMatrixLaboratories/~3/0I8HEmesDcs/twisted-1210pre1.html]]></link>
    <pubDate>2012-05-26 11:17:08</pubDate>
  </item>
  <item>
    <title><![CDATA[Terry Jones: Autovivification in Python: nested defaultdicts with a specific final type]]></title>
    <description><![CDATA[<p>I quite often miss the flexibility of <a href="http://en.wikipedia.org/wiki/Autovivification">autovivification</a> in <a href="http://python.org">Python</a>. That Wikipedia link shows a cute way to get what Perl has:</p>
<div class="dean_ch">
<span class="kw1">from</span> <span class="kw3">collections</span> <span class="kw1">import</span> defaultdict</div>
<p><span class="kw1">def</span> tree<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="kw1">return</span> defaultdict<span class="br0">&#40;</span>tree<span class="br0">&#41;</span></p>
<p>lupin = tree<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
lupin<span class="br0">&#91;</span><span class="st0">&quot;express&quot;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span> = <span class="st0">&quot;stand and deliver&quot;</span></p>
<p>It&#8217;s interesting to think about what&#8217;s going on in the above code and why it works. I really like defaultdict.</p>
<p>What I more often want, though, is not infinitely deep nested dictionaries like the above, but a (known) finite number of nested defaultdicts with a specific type at the final level. Here&#8217;s a tiny function I wrote to get just that:</p>
<div class="dean_ch">
<span class="kw1">from</span> <span class="kw3">collections</span> <span class="kw1">import</span> defaultdict</div>
<p><span class="kw1">def</span> autovivify<span class="br0">&#40;</span>levels=<span class="nu0">1</span>, final=<span class="kw2">dict</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span>defaultdict<span class="br0">&#40;</span>final<span class="br0">&#41;</span> <span class="kw1">if</span> levels &lt; <span class="nu0">2</span> <span class="kw1">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defaultdict<span class="br0">&#40;</span><span class="kw1">lambda</span>: autovivify<span class="br0">&#40;</span>levels &#8211; <span class="nu0">1</span>, final<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span></p>
<p>So let&#8217;s say you were counting the number of occurrences of words said by people by year, month, and day in a chat room. You&#8217;d write:</p>
<div class="dean_ch">
words = autovivify<span class="br0">&#40;</span><span class="nu0">5</span>, <span class="kw2">int</span><span class="br0">&#41;</span></div>
<p>words<span class="br0">&#91;</span><span class="st0">&quot;sam&quot;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">2012</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">5</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">25</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&quot;hello&quot;</span><span class="br0">&#93;</span> += <span class="nu0">1</span><br />
words<span class="br0">&#91;</span><span class="st0">&quot;sue&quot;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">2012</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">5</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="nu0">24</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&quot;today&quot;</span><span class="br0">&#93;</span> += <span class="nu0">1</span></p>
<p>Etc.  It&#8217;s pretty trivial, but it was fun to think about how to do it with a function and to play with some alternatives. You could do it manually with nested lambdas:</p>
<div class="dean_ch">
words = defaultdict<span class="br0">&#40;</span><span class="kw1">lambda</span>: defaultdict<span class="br0">&#40;</span><span class="kw2">int</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
words<span class="br0">&#91;</span><span class="st0">&quot;sam&quot;</span><span class="br0">&#93;</span><span class="br0">&#91;</span><span class="st0">&quot;hello&quot;</span><span class="br0">&#93;</span> += <span class="nu0">1</span></div>
<p>But that gets messy quickly and isn&#8217;t nearly as much fun.</p>]]></description>
    <link><![CDATA[http://blogs.fluidinfo.com/terry/2012/05/26/autovivification-in-python-nested-defaultdicts-with-a-specific-final-type/]]></link>
    <pubDate>2012-05-25 23:10:12</pubDate>
  </item>
  <item>
    <title><![CDATA[Mike Driscoll: wxPython: How to use the Clipboard]]></title>
    <description><![CDATA[<p>Everyone who uses computers regularly knows that they can copy and paste text. What they might not know is that when you copy something, it goes into a location known as the &#8220;clipboard&#8221;. Most programs provide access to a clipboard of some sort, whether it be just within the program itself or to the system clipboard, which allows items to be copied to other applications. The wxPython GUI toolkit also provides clipboard access, which you can use to copy text to and from within your program and even to the system clipboard. You can also copy images to the clipboard. In this tutorial, we&#8217;ll take a look at how you can do this in your own code.<span id="more-2351"></span></p>
<p><a href="http://www.blog.pythonlibrary.org/wp-content/uploads/2012/05/clipboard_tutorial.png"><img src="http://www.blog.pythonlibrary.org/wp-content/uploads/2012/05/clipboard_tutorial.png" alt="" title="clipboard_tutorial.png" width="401" height="251" class="aligncenter size-full wp-image-2382" /></a></p>
<p>We&#8217;ll start out with a really simple example code snippet. The following contains two buttons, one which copies any text that&#8217;s added to the text control and which you can then paste elsewhere, such as in the text box, in a search engine or whatever. The other button also copies to clipboard and then closes the application after flushing the data. This is supposed to make the data available in the system clipboard even after the application is closed. Both work great on Windows, but wxGTK (i.e. the Linux version) doesn&#8217;t work in the latter case. See the <a href="http://trac.wxwidgets.org/ticket/10515" target="_blank">bug ticket</a> for more information.</p>
<p>Anyway, let&#8217;s look at the code!</p>
<pre class="python"><span>import</span> wx
&nbsp;
<span>########################################################################</span>
<span>class</span> ClipboardPanel<span>&#40;</span>wx.<span>Panel</span><span>&#41;</span>:
    <span>&quot;&quot;</span><span>&quot;&quot;</span><span>&quot;&quot;</span>
&nbsp;
    <span>#----------------------------------------------------------------------</span>
    <span>def</span> <span>__init__</span><span>&#40;</span><span>self</span>, parent<span>&#41;</span>:
        <span>&quot;&quot;</span><span>&quot;Constructor&quot;</span><span>&quot;&quot;</span>
        wx.<span>Panel</span>.<span>__init__</span><span>&#40;</span><span>self</span>, parent<span>&#41;</span>
&nbsp;
        lbl = wx.<span>StaticText</span><span>&#40;</span><span>self</span>, label=<span>&quot;Enter text to copy to clipboard:&quot;</span><span>&#41;</span>
        <span>self</span>.<span>text</span> = wx.<span>TextCtrl</span><span>&#40;</span><span>self</span>, style=wx.<span>TE_MULTILINE</span><span>&#41;</span>
        copyBtn = wx.<span>Button</span><span>&#40;</span><span>self</span>, label=<span>&quot;Copy&quot;</span><span>&#41;</span>
        copyBtn.<span>Bind</span><span>&#40;</span>wx.<span>EVT_BUTTON</span>, <span>self</span>.<span>onCopy</span><span>&#41;</span>
        copyFlushBtn = wx.<span>Button</span><span>&#40;</span><span>self</span>, label=<span>&quot;Copy and Flush&quot;</span><span>&#41;</span>
        copyFlushBtn.<span>Bind</span><span>&#40;</span>wx.<span>EVT_BUTTON</span>, <span>self</span>.<span>onCopyAndFlush</span><span>&#41;</span>
&nbsp;
        sizer = wx.<span>BoxSizer</span><span>&#40;</span>wx.<span>VERTICAL</span><span>&#41;</span>
        sizer.<span>Add</span><span>&#40;</span>lbl, <span>0</span>, wx.<span>ALL</span>, <span>5</span><span>&#41;</span>
        sizer.<span>Add</span><span>&#40;</span><span>self</span>.<span>text</span>, <span>1</span>, wx.<span>EXPAND</span><span>&#41;</span>
        sizer.<span>Add</span><span>&#40;</span>copyBtn, <span>0</span>, wx.<span>ALL</span>|wx.<span>CENTER</span>, <span>5</span><span>&#41;</span>
        sizer.<span>Add</span><span>&#40;</span>copyFlushBtn, <span>0</span>, wx.<span>ALL</span>|wx.<span>CENTER</span>, <span>5</span><span>&#41;</span>
        <span>self</span>.<span>SetSizer</span><span>&#40;</span>sizer<span>&#41;</span>
&nbsp;
    <span>#----------------------------------------------------------------------</span>
    <span>def</span> onCopy<span>&#40;</span><span>self</span>, event<span>&#41;</span>:
        <span>&quot;&quot;</span><span>&quot;&quot;</span><span>&quot;&quot;</span>
        <span>self</span>.<span>dataObj</span> = wx.<span>TextDataObject</span><span>&#40;</span><span>&#41;</span>
        <span>self</span>.<span>dataObj</span>.<span>SetText</span><span>&#40;</span><span>self</span>.<span>text</span>.<span>GetValue</span><span>&#40;</span><span>&#41;</span><span>&#41;</span>
        <span>if</span> wx.<span>TheClipboard</span>.<span>Open</span><span>&#40;</span><span>&#41;</span>:
            wx.<span>TheClipboard</span>.<span>SetData</span><span>&#40;</span><span>self</span>.<span>dataObj</span><span>&#41;</span>
            wx.<span>TheClipboard</span>.<span>Close</span><span>&#40;</span><span>&#41;</span>
        <span>else</span>:
            wx.<span>MessageBox</span><span>&#40;</span><span>&quot;Unable to open the clipboard&quot;</span>, <span>&quot;Error&quot;</span><span>&#41;</span>
&nbsp;
    <span>#----------------------------------------------------------------------</span>
    <span>def</span> onCopyAndFlush<span>&#40;</span><span>self</span>, event<span>&#41;</span>:
        <span>&quot;&quot;</span><span>&quot;&quot;</span><span>&quot;&quot;</span>
        <span>self</span>.<span>dataObj</span> = wx.<span>TextDataObject</span><span>&#40;</span><span>&#41;</span>
        <span>self</span>.<span>dataObj</span>.<span>SetText</span><span>&#40;</span><span>self</span>.<span>text</span>.<span>GetValue</span><span>&#40;</span><span>&#41;</span><span>&#41;</span>
        <span>if</span> wx.<span>TheClipboard</span>.<span>Open</span><span>&#40;</span><span>&#41;</span>:
            wx.<span>TheClipboard</span>.<span>SetData</span><span>&#40;</span><span>self</span>.<span>dataObj</span><span>&#41;</span>
            wx.<span>TheClipboard</span>.<span>Flush</span><span>&#40;</span><span>&#41;</span>
        <span>else</span>:
            wx.<span>MessageBox</span><span>&#40;</span><span>&quot;Unable to open the clipboard&quot;</span>, <span>&quot;Error&quot;</span><span>&#41;</span>
&nbsp;
        <span>self</span>.<span>GetParent</span><span>&#40;</span><span>&#41;</span>.<span>Close</span><span>&#40;</span><span>&#41;</span>
&nbsp;
<span>########################################################################</span>
<span>class</span> ClipboardFrame<span>&#40;</span>wx.<span>Frame</span><span>&#41;</span>:
    <span>&quot;&quot;</span><span>&quot;&quot;</span><span>&quot;&quot;</span>
&nbsp;
    <span>#----------------------------------------------------------------------</span>
    <span>def</span> <span>__init__</span><span>&#40;</span><span>self</span><span>&#41;</span>:
        <span>&quot;&quot;</span><span>&quot;Constructor&quot;</span><span>&quot;&quot;</span>
        wx.<span>Frame</span>.<span>__init__</span><span>&#40;</span><span>self</span>, <span>None</span>, title=<span>&quot;Clipboard Tutorial&quot;</span><span>&#41;</span>
        panel = ClipboardPanel<span>&#40;</span><span>self</span><span>&#41;</span>
        <span>self</span>.<span>Show</span><span>&#40;</span><span>&#41;</span>
&nbsp;
&nbsp;
<span>if</span> __name__ == <span>&quot;__main__&quot;</span>:
    app = wx.<span>App</span><span>&#40;</span><span>False</span><span>&#41;</span>
    frame = ClipboardFrame<span>&#40;</span><span>&#41;</span>
    app.<span>MainLoop</span><span>&#40;</span><span>&#41;</span></pre>
<p>As you might have guessed, the guts of this script are in the button event handlers. The main bit is <strong>wx.TextDataObject</strong> which will store the data from the text control. Next we attempt to open the clipboard. If we&#8217;re successful, we add our text to the clipboard and then close it. The data is now there for the pasting. The second event handler does the same thing, but it Flushes to the clipboard rather than just closing it. If you wanted to copy a bitmap instead, then you&#8217;d want to use a <strong>wx.BitmapDataObject</strong> and pass it an <strong>wx.Bitmap</strong> object. Otherwise, the rest is the same.</p>
<h3>Wrapping Up</h3>
<p>Now you know how to use the clipboard from wxPython! Get out there and start creating something to amaze your friends and strangers alike!</p>
<h3>Additional Resources</h3>
<ul>
<li>The wx.Clipboard <a href="http://wxpython.org/docs/api/wx.Clipboard-class.html" target="_blank">documentation</a></li>
<li>The wxPython <a href="http://wiki.wxpython.org/ClipBoard" target="_blank">wiki page</a> on the Clipboard</li>
</ul>]]></description>
    <link><![CDATA[http://www.blog.pythonlibrary.org/2012/05/25/wxpython-how-to-use-the-clipboard/]]></link>
    <pubDate>2012-05-25 20:45:49</pubDate>
  </item>
  <item>
    <title><![CDATA[Kristján Valur: Optimizing Python Condition Variables with Telemetry]]></title>
    <description><![CDATA[<p>Working in a games company often allows you to work with the coolest toys.  One of these is a product caled <a href="http://www.radgametools.com/telemetry.htm">Telemetry</a> from <a href="http://www.radgametools.com">Rad Game Tools</a>.<br />
<span id="more-213"></span></p>
<h2>Python integration</h2>
<p>We&#8217;ve integrated Telemetry into the game engine for performance evaluation purposes. As part of this, I also integrated it to the Python library. I wrote a special &#8220;TelemetryProfiler&#8221; class that we can use with <strong>sys.setprofile()</strong> so that .py excecution can be monitored. In addition, I added some select monitoring hooks into the core engine, and around such places as locks and for memory allocations.</p>
<p>To work well with threads and <em>tasklets</em>, we maded some changes to allow for <em>global profiling</em>. Using a flag called <strong>stackless.globaltrace</strong>, <strong>sys.setprofile()</strong> (and <strong>sys.settrace()</strong>) have global effects on both all tasklets and all threads. The profiling flag is stored in the interpreter state so that new threads will inherit it, and currently executing threads will have it set by traversing the list of existing threads. This allows us to turn profiling on and off in an executing program and monitor all that the python engine is doing.</p>
<p>For profiling stackless tasklets, we had to resort to trickery. Because Telemetry knows about threads, but not microthreads, we had to add code to recognize the currently running tasklet, and unwind and replay the context stack as necessary whenever at tasklet switch occurred.</p>
<p>Here is a snapshot of parts of a Python execution as it is displayed in the Telemetry vizualizer:</p>
<div id="attachment_216" class="wp-caption alignnone"><a href="http://blog.ccpgames.com/kristjan/files/2012/05/1.jpg"><img class="size-large wp-image-216" src="http://blog.ccpgames.com/kristjan/files/2012/05/1-1024x596.jpg" alt="" width="640" height="372" /></a><p class="wp-caption-text">Python running on the main thread</p></div>
<p>Notice the hierarchical call graph. Tooltips will show more information about each field, such as Python source file and line number. The Mem Events bar at the bottom shows all memory allocations made and the lifetime of each of them.<br />
Notice also the red blips. These are the <em>GIL</em> being ticked (there is definitely room for a faster GIL tick function. We already treat the GIL differently from other locks and an optimized Tick is simple to add. Later.)</p>
<h2>Condition Variables.</h2>
<p>As previously mentioned on this blog, we have to perform HTTP requests on worker threads and then communicate the results back to the main tasklet. The worker threads live in a threadpool and receive work from any client thread. Dispatching of work requests is done using the tried and tested <em>Condition Variable</em> model, using the <strong>threading.Condition</strong> class and an associated <strong>threading.RLock</strong> object. Workers wait on condition variables until they are woken up and see that there is work to be done, at which point they pull work off a queue, release the lock, perform the work, and then do it again.</p>
<p>To lower latency, it is important that this dispatching of work to the worker thread happens as soon as possible. Ideally, it should happen immediately, the worker grabbing the GIL, kicking the HTTP Request into action, releaseing the GIL and blocking. To see if things were progressing in a timely manner, I examined the process using Telemetry.</p>
<p>First off, I should explain what locking model we are using. The PS3 is essentially posix-like, so locks (and the GIL) are implemented using the <strong>thread_pthread.h</strong> file. The default choice in there is to use the posix <em>semaphore</em> API to implement the non-recursive locks Python uses. But I was quickly slapped by the engine profilers when they started seeing all those kernel transitions coming out of Python. Aqcuiring a free lock, and ticking the GIL, when these are based on a semaphore, incurs a kernel transition and scheduling and whatnot, a high price to pay when there is no contention.  This lights up red in all performance measurement tools. So, we opted for using the mutex/condition implementation also provided. Why this is not the default in Python is beyond me, since it is much faster.</p>
<p>So, anyway, this is what waking up on a condition variable looks like in Telemetry. The worker thread has been waiting on a <strong>threading.Condition</strong> object. The main posts a request and the worker wakes up.</p>
<div id="attachment_219" class="wp-caption alignnone"><a href="http://blog.ccpgames.com/kristjan/files/2012/05/2.jpg"><img class="size-large wp-image-219" src="http://blog.ccpgames.com/kristjan/files/2012/05/2-1024x385.jpg" alt="" width="640" height="240" /></a><p class="wp-caption-text">Waking up from the condition variable</p></div>
<p>What you see on the left is an <strong>acquire()</strong> in progress. This is the Lock object that the condition variable uses to sleep on. Then, we<strong> _acuire_restore()</strong>, then some logging code and finally the httpRequest being sent.  (Ignore the logging code and its associated GIL delay, it is only used during debugging.)<br />
Zooming in a bit, brings more detail:</p>
<div id="attachment_221" class="wp-caption alignnone"><a href="http://blog.ccpgames.com/kristjan/files/2012/05/3.jpg"><img class="size-large wp-image-221" src="http://blog.ccpgames.com/kristjan/files/2012/05/3-1024x189.jpg" alt="" width="640" height="118" /></a><p class="wp-caption-text">detail of wakeup</p></div>
<p>What you see here, is the GIL being acquired two times: Once to complete the <strong>Lock.acquire()</strong> call which is done in <strong>Condition.wait()</strong>, and once to re-acquire the lock associated with the condition variable (typically an <strong>RLock</strong>): To complete the condition variable protocol and return from <strong>wait()</strong> with the lock held.</p>
<p>Now, in a multithreaded program, the GIL is <em>always in contention</em>. Releasing and reaquiring the GIL two times instead of once will therefore add unnecessary latency into this code. If this second GIL aquisition were skipped, this wakeup delay would have been shortened by 10 milliseconds, kicking off the http request that much faster.</p>
<h2>Optimization one: _acquire_cv()</h2>
<p>The first obvious thing to do is to roll this double acquisition of a lock into one. There are two locks that need to be acquired here, the <em>wait</em> lock and the lock associated with the <strong>Condition</strong> object. There is no reason they can&#8217;t be both acquired in one swell foop.</p>
<p>I did this by adding a new method to the Lock class in <strong>thread.c</strong>: <strong>_acquire_cv()</strong> takes an additional Lock object which is always acquired before returning from the function, except when the a try-aquire fails (to support the emulated timeout behaviour.)</p>
<p>Now, if the outer lock is acquired on return, there is no need for an <strong>_acquire_restore()</strong> call in threading.py, so this has been replaced with a <strong>_restore()</strong> call, which merely sets the internal variables on an already acquired lock.</p>
<p>This is what the new <strong>Condition.wait</strong> call looks like:</p>
<pre class="brush: python">
    def wait2(self, timeout=None):
        if not self._is_owned():
            raise RuntimeError(&quot;cannot wait on un-acquired lock&quot;)
        waiter = _allocate_lock()
        waiter.acquire()
        self.__waiters.append(waiter)
        saved_state = self._release_save()
        gotit = 0
        try:    # restore state no matter what (e.g., KeyboardInterrupt)
            if timeout is None:
                gotit = waiter._acquire_cv(1, saved_state[0])
                if __debug__:
                    self._note(&quot;%s.wait(): got it&quot;, self)
            else:
                pass # removed for brevity
        finally:
            if gotit:
                self._restore(saved_state)
            else:
                self._acquire_restore(saved_state)

    wait = wait2
</pre>
<p>With this in place, things look a little different:<br />
<a href="http://blog.ccpgames.com/kristjan/files/2012/05/4.jpg"><img class="alignnone size-large wp-image-225" src="http://blog.ccpgames.com/kristjan/files/2012/05/4-1024x606.jpg" alt="" width="640" height="378" /></a><br />
On the bottom left, two Lock regions are visible (this is when acquiring a thread.Lock object.). Once the first has been acuired, i.e. the wakeup signal recieved, it proceeds to aquire the outer lock. This succeeds once the first thread (above in the picture) has released it, in the <strong>__exit__</strong> method of a context manager. Once that is done, a single GIL reaquisition is performed. Now, this one is fairly short and some can be longer than this, but it is clear that doing this once, rather than twice is beneficial since it reduces the thrashing of threads involved.</p>
<p>This simple change is really easy to implement. the <strong>_acquire_cv()</strong> function is simple, and the <strong>wait2()</strong> function is simpler than the <strong>wait()</strong> function in <strong>threading.py</strong>. This is something I&#8217;d immediately recommend for cPython.</p>
<h2>Native Condition objects</h2>
<p>So, is there anything else that can be done? Yes there is. The <strong>Condition</strong> class is implemented in <strong>threading.py</strong> by using Python&#8217;s native non-recursive locks (semantically, they are semaphores with a max value of 1) and juggling a queue and waking things up. This is what calling <strong>condition.wait()</strong> looks like:</p>
<div id="attachment_228" class="wp-caption alignnone"><a href="http://blog.ccpgames.com/kristjan/files/2012/05/wait.jpg"><img class="size-large wp-image-228" src="http://blog.ccpgames.com/kristjan/files/2012/05/wait-1024x297.jpg" alt="" width="640" height="185" /></a><p class="wp-caption-text">calling condition.wait()</p></div>
<p>On the left, there is a lot of action where a <strong>Lock </strong>object that is used for waiting is being created and put into a list. Then there is a long stall when the initial lock is aquired. Why is that? It&#8217;s because every <strong>Lock.acquire()</strong> releases the GIL, even if the lock is uncontested. It is the nature of the internal architecture of cPython that Lock objects are GIL unaware, so the GIL manipulation must be done outside of them. So, to aquire our our new wait object, the GIL is released, the lock acquired, and then the GIL must be reaquired.</p>
<p>It would be possible here to use the new <strong>_acquire_cv()</strong> to do this without releasing the GIL, perhaps by passing <strong>None</strong> as its second argument. But since I&#8217;m already using Locks based on mutexes and condition variables, why not simply implement a <em>native</em> <strong>Condition</strong> object? Doing that would rid us of most of the annoying code in <strong>threading.Condition</strong>. No need to create a Lock object for every wait, manage a queue, and potentially leave Lock object in an aquired state when destroying them (yes, the timeout version of Condition variables in Python 3 has that race problem.) Also, we would get the built-in timeout mechanism of all condition variable implementations I&#8217;ve seen for free.</p>
<p>Since the native Python lock objects are non-recursive, unlike classical mutex objects as used with condition variables, blocking is implemented with an internal Condition variable for each lock. So, a native thread.Condition class&#8217;s <strong>wait()</strong> method cannot directly just pass in a mutex. Instead, we must roll some of our lock<strong> release()</strong> and <strong>acquire()</strong> release machinery into the <strong>wait()</strong> and <strong>notify()</strong> functions.</p>
<p>This is what the <strong>thread.Condition.wait()</strong> function looks like:</p>
<pre class="brush: c">
int
PyThread_cond_wait(PyThread_type_condition *cond, PyThread_type_lock lock, double timeout)
{

    /* Release the Lock, keeping the Mutex held */
     * no need to release GIL here, this is a short lived thing
     */
    pthread_lock *thelock = (pthread_lock *)lock;
    int status;
    PyTmEnter(PYTM_ENTER_IDLE, &quot;COND&quot;);
    status = pthread_mutex_lock( &amp;amp;thelock-&gt;mut );
    CHECK_STATUS_COND;
    if (!thelock-&gt;locked) {
        pthread_mutex_unlock( &amp;amp;thelock-&gt;mut );
        PyErr_SetString(PyExc_RuntimeError, &quot;cannot wait on un-acquired lock&quot;);
        return -1;
    }
    thelock-&gt;locked = 0;
    status  = pthread_cond_signal(&amp;amp;thelock-&gt;lock_released);
    if (status) {
        thelock-&gt;locked = 1;
        pthread_mutex_unlock( &amp;amp;thelock-&gt;mut );
        CHECK_STATUS_COND;
    }
    /* now, wait for the condition variable */
    Py_BEGIN_ALLOW_THREADS
    if (timeout &gt;= 0) {
        struct timespec ts;
#if SN_TARGET_PS3
        sys_time_sec_t sec;
        sys_time_nsec_t nsec;
        sys_time_get_current_time(&amp;amp;sec, &amp;amp;nsec);
        ts.tv_sec = sec;
        ts.tv_nsec = nsec;
#endif /* todo: implement posix */

        ts.tv_sec += (int)timeout;
        ts.tv_nsec += (int) 1e9 * (timeout - (double)(int)timeout);
        status = pthread_cond_timedwait(cond, &amp;amp;thelock-&gt;mut, &amp;amp;ts);
        if (status == ETIMEDOUT)
            status = 0; /* don&#039;t specifically signal this */
    } else {
        status = pthread_cond_wait(cond, &amp;amp;thelock-&gt;mut);
    }
    /* now, reacquire the lock.  We already hold the mutex. */
    while (thelock-&gt;locked) {
        int status2 = pthread_cond_wait(&amp;amp;thelock-&gt;lock_released, &amp;amp;thelock-&gt;mut);
        if (status2) {
            if (!status)
                status = status2; /* otherwise, ignore this error */
            break;
        }
    }
    thelock-&gt;locked = 1;
    pthread_mutex_unlock( &amp;amp;thelock-&gt;mut );
    Py_END_ALLOW_THREADS
    PyTmLeave();
    CHECK_STATUS_COND;
    return 0;
}
</pre>
<p>Similarly, the <strong>notify()</strong> method must hold the mutex when called:</p>
<pre class="brush: c">
static int
_PyThread_cond_notify_some(PyThread_type_condition *cond, PyThread_type_lock lock, int all)
{
    pthread_lock *thelock = (pthread_lock *)lock;
    int status = pthread_mutex_lock( &amp;amp;thelock-&gt;mut );
    CHECK_STATUS_COND;
    if (!thelock-&gt;locked) {
        pthread_mutex_unlock( &amp;amp;thelock-&gt;mut );
        PyErr_SetString(PyExc_RuntimeError, &quot;cannot notify on un-acquired lock&quot;);
    }
    if (all)
        status = pthread_cond_broadcast(cond);
    else
        status = pthread_cond_signal(cond);
    pthread_mutex_unlock( &amp;amp;thelock-&gt;mut );
    CHECK_STATUS_COND;
    return 0;
}
</pre>
<p>So, what effect does this have? This is what thread.Condition.wait() looks like in telemetry:</p>
<div id="attachment_234" class="wp-caption alignnone"><a href="http://blog.ccpgames.com/kristjan/files/2012/05/conditionwait.jpg"><img class="size-large wp-image-234  " src="http://blog.ccpgames.com/kristjan/files/2012/05/conditionwait.jpg" alt="" width="812" height="358" /></a><p class="wp-caption-text">thread.Condition.wait()</p></div>
<p>There are some blips on the left when calling the initial predicate in the <strong>wait_for_condition(</strong>) function and the call of the <strong>threading.RLock._save()</strong> method (to store the recursion state of the <strong>RLock</strong>.) There is no unnecessary flapping of the GIL.</p>
<p>When waking up, it looks like this when the <strong>notify()</strong> call is made from the main thread:</p>
<div id="attachment_246" class="wp-caption alignnone"><a href="http://blog.ccpgames.com/kristjan/files/2012/05/wakeup013.jpg"><img class="size-full wp-image-246 " src="http://blog.ccpgames.com/kristjan/files/2012/05/wakeup013.jpg" alt="" width="1006" height="687" /></a><p class="wp-caption-text">calling tread.Condition.wait()</p></div>
<p>And here the worker finally aquires the GIL:</p>
<div id="attachment_239" class="wp-caption alignnone"><a href="http://blog.ccpgames.com/kristjan/files/2012/05/wakeup02.jpg"><img class="size-large wp-image-239" src="http://blog.ccpgames.com/kristjan/files/2012/05/wakeup02-1024x336.jpg" alt="" width="640" height="210" /></a><p class="wp-caption-text">GIL aquired and wait() returns</p></div>
<p>Internally, the <strong>notify()</strong> call causes the native condition variable to wake up. The delay until it tries to reaquire the GIL is the when it is trying to aquire the associated <strong>RLock</strong> object. Then once the GIL is finally aqcuired, there is a call to _restore (to restore the recursion state of the <strong>RLock</strong>) and a finall call to the predicate function to make sure that the the external conditions are now satisfied. In the whole<strong> wait()</strong> and <strong>notify()</strong> process, there is no GIL trashing whatsoever.</p>
<h2>Conclusion</h2>
<p>It is fairly straightforward to modify the native locks in Python to cater to the special semantics required for threading.Condition objects, by adding a special method to acquire two locks at once, and also by acquiring a lock that is known to be uncontested by not releasing the GIL.</p>
<p>For those lock implementations that rely on mutexes and condition variables, it is also simple to provide a native implementation of a Condition object.  Currently this applies to pthreads only, but I have a condition variable / mutex locking implementation <a href="http://bugs.python.org/issue11618">waiting in the wings for Windows</a>, which would make the same thing possible there (and in fact our CCP branch of cPython 2.7 does just that).</p>
<p><strong>threading.py</strong> can easily use these new features if available and fall back to the old behaviour if not.</p>
<p>The only semantic change when providing a native Condition variable is that then the python condition variable may become subject to <em>spurious wakeup</em>. While python has never promised that spurious wakeup cannot occur, the implementation in threading.py has been free of it.  However, the condition variable, as derived from the <a href="http://en.wikipedia.org/wiki/Monitor_(synchronization)">monitor</a> concept, has always been careful to allow for spurious wakeups as a possibility.  <a href="http://stackoverflow.com/questions/8594591/why-does-pthread-cond-wait-have-spurious-wakeups">There are good reasons for it</a>, and since <em>stolen wakeups</em> are always a possibility regardless, and the <em>correct</em> way of using wait() is in a loop, checking an external condition, it does not matter to the conforming programmer.</p>
<p>We&#8217;ll be going forward by using the native Condition implementation on the PS3 to increase synergy, and drill down to better leverage towards a procured paradigm shift vis-à-vis a deliverable home run.</p>]]></description>
    <link><![CDATA[http://blog.ccpgames.com/kristjan/2012/05/25/optimizing-python-condition-variables-with-telemetry/]]></link>
    <pubDate>2012-05-25 15:55:30</pubDate>
  </item>
  <item>
    <title><![CDATA[Just a little Python: GridFS: The MongoDB Filesystem]]></title>
    <description><![CDATA[<p>In some previous posts on <a href="http://blog.pythonisito.com/2012/01/getting-started-with-mongodb-and-python.html">mongodb and python</a> and
<a href="http://blog.pythonisito.com/2012/01/moving-along-with-pymongo.html">pymongo</a>, I introduced the NoSQL database <a href="http://www.mongodb.org/">MongoDB</a> and how
you can use it from Python. This post goes beyond the basics of MongoDB and
<a href="http://api.mongodb.org/python/">pymongo</a> to give you a taste for MongoDB's take on filesystems,
<a href="http://www.mongodb.org/display/DOCS/GridFS">GridFS</a>.</p>
<a name="more"></a>

<h2>Why a filesystem?</h2>
<p>If you've been doing MongoDB for a while, you may have heard about the 16 MB
document size limit. When I started using MongoDB (around version 0.8), the limit
was actually 4 MB. What this means is that everything is working just fine, your
system is screaming fast, until you try to create a document that's 4.001 MB and
<em>boom</em> nothing works any more. For us at <a href="http://sf.net">SourceForge</a>, what that meant was
that we had to restructure our schema and use less embedding.</p>
<p>But what if it's not something that can be restructured? Maybe your site allows
users to upload large attachments of unknown size. In such cases you <em>probably</em>
can get away with using a <code>Binary</code> field type and crossing your fingers, but a
better solution, in my opinion, is to actually store the contents your upload in
a series of documents (let's call them "chunks") of limited size. Then you can
tie them all together with another document that specifies all the file
metadata.</p>
<h2>GridFS to the rescue</h2>
<p>Well, that's exactly what GridFS does, but it does it with a nice API with a few
more bells and whistles than you'd probably build on your own.  It's important to
note that GridFS, implemented in all the MongoDB language drivers, is a
<em>convention</em> and an <em>api</em>, not something that's provided natively by the
server. As far as the server is concerned, it's all just collections and
documents.</p>
<h3>The GridFS schema</h3>
<p>GridFS actually stores your files in two collections, named by default <code>fs.files</code>
and <code>fs.chunks</code>, although you can change the <code>fs</code> to something else if you'd
like. The <code>fs.files</code> collection is where reading or writing a file begins. A
typical <code>fs.files</code> document looks like the following (<a href="http://www.mongodb.org/display/DOCS/GridFS+Specification">credit</a>):</p>
<div class="codehilite"><pre><span class="p">{</span>
  <span class="c1">// unique ID for this file</span>
  <span class="s2">&quot;_id&quot;</span> <span class="o">:</span> <span class="o">&lt;</span><span class="nx">unspecified</span><span class="o">&gt;</span><span class="p">,</span>
  <span class="c1">// size of the file in bytes</span>
  <span class="s2">&quot;length&quot;</span> <span class="o">:</span> <span class="nx">data_number</span><span class="p">,</span>
  <span class="c1">// size of each of the chunks.  Default is 256k</span>
  <span class="s2">&quot;chunkSize&quot;</span> <span class="o">:</span> <span class="nx">data_number</span><span class="p">,</span>
  <span class="c1">// date when object first stored</span>
  <span class="s2">&quot;uploadDate&quot;</span> <span class="o">:</span> <span class="nx">data_date</span><span class="p">,</span>
  <span class="c1">// result of running the &quot;filemd5&quot; command on this file's chunks</span>
  <span class="s2">&quot;md5&quot;</span> <span class="o">:</span> <span class="nx">data_string</span>
<span class="p">}</span>
</pre></div>


<p>The <code>fs.chunks</code> collection contains all the data for your files:</p>
<div class="codehilite"><pre><span class="p">{</span>
  <span class="c1">// object id of the chunk in the _chunks collection</span>
  <span class="s2">&quot;_id&quot;</span> <span class="o">:</span> <span class="o">&lt;</span><span class="nx">unspecified</span><span class="o">&gt;</span><span class="p">,</span>
  <span class="c1">// _id of the corresponding files collection entry</span>
  <span class="s2">&quot;files_id&quot;</span> <span class="o">:</span> <span class="o">&lt;</span><span class="nx">unspecified</span><span class="o">&gt;</span><span class="p">,</span>
  <span class="c1">// chunks are numbered in order, starting with 0</span>
  <span class="s2">&quot;n&quot;</span> <span class="o">:</span> <span class="nx">chunk_number</span><span class="p">,</span>
  <span class="c1">// the chunk's payload as a BSON binary type</span>
  <span class="s2">&quot;data&quot;</span> <span class="o">:</span> <span class="nx">data_binary</span><span class="p">,</span>
<span class="p">}</span>
</pre></div>


<p>In the <a href="http://api.mongodb.org/python/current/api/gridfs/index.html">Python gridfs package</a> (included with the pymongo driver), several other
fields are inserted as well:</p>
<dl>
<dt><code>filename</code></dt>
<dd>This is the 'human' name for the file, which may be path-delimited to simulate
  directories.</dd>
<dt><code>contentType</code></dt>
<dd>This is the mime-type of the file</dd>
<dt><code>encoding</code></dt>
<dd>This is the unicode encoding used for text files.</dd>
</dl>
<p>You can also add in your own attributes to files. At SourceForge, we used things
like <code>project_id</code> or <code>forum_id</code> to allow the same filename to be uploaded to  multiple
places on the site without worrying about namespace collisions. To keep your code
future-proof, you should put any custom attributes inside an embedded <code>metadata</code>
document, just in case the gridfs spec expands to incorporate more fields.</p>
<h2>Using GridFS</h2>
<p>So with all that out of the way, how to you actually <em>use</em> GridFS? It's actually
pretty straightforward. The first thing you need is a reference to a GridFS
filesystem:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">pymongo</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">gridfs</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">conn</span> <span class="o">=</span> <span class="n">pymongo</span><span class="o">.</span><span class="n">Connection</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">db</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">gridfs_test</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span> <span class="o">=</span> <span class="n">gridfs</span><span class="o">.</span><span class="n">GridFS</span><span class="p">(</span><span class="n">db</span><span class="p">)</span>
</pre></div>


<h3>Basic reading and writing</h3>
<p>Once you have the filesystem, you can start putting stuff in it:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">with</span> <span class="n">fs</span><span class="o">.</span><span class="n">new_file</span><span class="p">()</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>
<span class="gp">... </span>    <span class="n">fp</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">'This is my new file. It is teh awezum!'</span><span class="p">)</span>
</pre></div>


<p>Let's examine the underlying collections to see what actually happened:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="nb">list</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">fs</span><span class="o">.</span><span class="n">files</span><span class="o">.</span><span class="n">find</span><span class="p">())</span>
<span class="go">[{u'length': 38,</span>
<span class="go">  u'_id': ObjectId('4fbfa7b9fb72f096bd000000'),</span>
<span class="go">  u'uploadDate': datetime.datetime(2012, 5, 25, 15, 39, 37, 55000),</span>
<span class="go">  u'md5': u'332de5ca08b73218a8777da69293576a',</span>
<span class="go">  u'chunkSize': 262144}]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">list</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">fs</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">find</span><span class="p">())</span>
<span class="go">[{u'files_id': ObjectId('4fbfa7b9fb72f096bd000000'),</span>
<span class="go">  u'_id': ObjectId('4fbfa7b9fb72f096bd000001'),</span>
<span class="go">  u'data': Binary('This is my new file. It is teh awezum!', 0),</span>
<span class="go">  u'n': 0}]</span>
</pre></div>


<p>You can see that there's really nothing surprising or mysterious happening there;
it's just mapping the filesystem metaphor onto MongoDB documents. In this case,
our file was small enough that it didn't need to be split into chunks. We can
<em>force</em> split it by specifying a small <code>chunkSize</code> when creating the file:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">with</span> <span class="n">fs</span><span class="o">.</span><span class="n">new_file</span><span class="p">(</span><span class="n">chunkSize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>
<span class="gp">... </span>    <span class="n">fp</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">'This is file number 2. It should be split into several chunks'</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fp</span>
<span class="go">&lt;gridfs.grid_file.GridIn object at 0x1010f5950&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fp</span><span class="o">.</span><span class="n">_id</span>
<span class="go">ObjectId('4fbfa8ddfb72f0971c000000')</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">list</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">fs</span><span class="o">.</span><span class="n">chunks</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="n">files_id</span><span class="o">=</span><span class="n">fp</span><span class="o">.</span><span class="n">_id</span><span class="p">)))</span>
<span class="go">[{... u'data': Binary('This is fi', 0), u'n': 0},</span>
<span class="go"> {... u'data': Binary('le number ', 0), u'n': 1},</span>
<span class="go"> {... u'data': Binary('2. It shou', 0), u'n': 2},</span>
<span class="go"> {... u'data': Binary('ld be spli', 0), u'n': 3},</span>
<span class="go"> {... u'data': Binary('t into sev', 0), u'n': 4},</span>
<span class="go"> {... u'data': Binary('eral chunk', 0), u'n': 5},</span>
<span class="go"> {... u'data': Binary('s', 0), u'n': 6}]</span>
</pre></div>


<p>Now, if we actually want to read the file <em>as a file</em>, we'll need to use the
gridfs api:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">with</span> <span class="n">fs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">_id</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp_read</span><span class="p">:</span>
<span class="gp">... </span>    <span class="k">print</span> <span class="n">fp_read</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="gp">...</span>
<span class="go">This is file number 2. It should be split into several chunks</span>
</pre></div>


<h3>Treating it more like a filesystem</h3>
<p>There are several other convenience methods bundled into the <code>GridFS</code> object to
give more filesystem-like behavior. For instance, <code>new_file()</code> takes any number of
keyword arguments that will get added onto the <code>fs.files</code> document being created:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">with</span> <span class="n">fs</span><span class="o">.</span><span class="n">new_file</span><span class="p">(</span>
<span class="gp">... </span>    <span class="n">filename</span><span class="o">=</span><span class="s">'file.txt'</span><span class="p">,</span> 
<span class="gp">... </span>    <span class="n">content_type</span><span class="o">=</span><span class="s">'text/plain'</span><span class="p">,</span> 
<span class="gp">... </span>    <span class="n">my_other_attribute</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>
<span class="gp">... </span>    <span class="n">fp</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">'New file'</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fp</span>
<span class="go">&lt;gridfs.grid_file.GridIn object at 0x1010f59d0&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">fs</span><span class="o">.</span><span class="n">files</span><span class="o">.</span><span class="n">find_one</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="n">_id</span><span class="o">=</span><span class="n">fp</span><span class="o">.</span><span class="n">_id</span><span class="p">))</span>
<span class="go">{u'contentType': u'text/plain',</span>
<span class="go"> u'chunkSize': 262144,</span>
<span class="go"> u'my_other_attribute': 42,</span>
<span class="go"> u'filename': u'file.txt',</span>
<span class="go"> u'length': 8,</span>
<span class="go"> u'uploadDate': datetime.datetime(2012, 5, 25, 15, 53, 1, 973000),</span>
<span class="go"> u'_id': ObjectId('4fbfaaddfb72f0971c000008'), u'md5':</span>
<span class="go"> u'681e10aecbafd7dd385fa51798ca0fd6'}</span>
</pre></div>


<p>Better would be to encapsulate <code>my_other_attribute</code> into the <code>metadata</code> property:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">with</span> <span class="n">fs</span><span class="o">.</span><span class="n">new_file</span><span class="p">(</span>
<span class="gp">... </span>    <span class="n">filename</span><span class="o">=</span><span class="s">'file2.txt'</span><span class="p">,</span> 
<span class="gp">... </span>    <span class="n">content_type</span><span class="o">=</span><span class="s">'text/plain'</span><span class="p">,</span> 
<span class="gp">... </span>    <span class="n">metadata</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">my_other_attribute</span><span class="o">=</span><span class="mi">42</span><span class="p">))</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>
<span class="gp">... </span>    <span class="n">fp</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">'New file 2'</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">fs</span><span class="o">.</span><span class="n">files</span><span class="o">.</span><span class="n">find_one</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="n">_id</span><span class="o">=</span><span class="n">fp</span><span class="o">.</span><span class="n">_id</span><span class="p">))</span>
<span class="go">{u'contentType': u'text/plain',</span>
<span class="go"> u'chunkSize': 262144,</span>
<span class="go"> u'metadata': {u'my_other_attribute': 42},</span>
<span class="go"> u'filename': u'file2.txt',</span>
<span class="go"> u'length': 10,</span>
<span class="go"> u'uploadDate': datetime.datetime(2012, 5, 25, 15, 54, 5, 67000),</span>
<span class="go"> u'_id':ObjectId('4fbfab1dfb72f0971c00000a'),</span>
<span class="go"> u'md5': u'9e4eea3dec28d8346b52f18086437ac7'}</span>
</pre></div>


<p>We can also "overwrite" files by filename, but since GridFS actually indexes
files by <code>_id</code>, it doesn't get rid of the old file, it just <em>versions</em> it:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">with</span> <span class="n">fs</span><span class="o">.</span><span class="n">new_file</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s">'file.txt'</span><span class="p">,</span> <span class="n">content_type</span><span class="o">=</span><span class="s">'text/plain'</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>
<span class="gp">... </span>    <span class="n">fp</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">'Overwrite the so-called &quot;New file&quot;'</span><span class="p">)</span>
<span class="gp">...</span>
</pre></div>


<p>Now, if we want to retrieve the file by filename, we can use <code>get_version</code> or
<code>get_last_version</code>:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span><span class="o">.</span><span class="n">get_last_version</span><span class="p">(</span><span class="s">'file.txt'</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="go">'Overwrite the so-called &quot;New file&quot;'</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span><span class="o">.</span><span class="n">get_version</span><span class="p">(</span><span class="s">'file.txt'</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="go">'New file'</span>
</pre></div>


<p>Since we've been uploading files with a <code>filename</code> property, we can also <code>list</code>
the files in gridfs:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span><span class="o">.</span><span class="n">list</span><span class="p">()</span>
<span class="go">[u'file.txt', u'file2.txt']</span>
</pre></div>


<p>We can also <code>remove</code> files, of course:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">fp</span> <span class="o">=</span> <span class="n">fs</span><span class="o">.</span><span class="n">get_last_version</span><span class="p">(</span><span class="s">'file.txt'</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">_id</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span><span class="o">.</span><span class="n">list</span><span class="p">()</span>
<span class="go">[u'file.txt', u'file2.txt']</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span><span class="o">.</span><span class="n">get_last_version</span><span class="p">(</span><span class="s">'file.txt'</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="go">'New file'</span>
</pre></div>


<p>Note that since only one version of <code>"file.txt"</code> was removed, we still have a
file named <code>"file.txt"</code> in the filesystem.</p>
<p>Finally, gridfs also provides convenience methods for determining if a file
exists and for quickly writing a short file into grifs:</p>
<div class="codehilite"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">_id</span><span class="p">)</span>
<span class="go">False</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s">'file.txt'</span><span class="p">)</span>
<span class="go">True</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span><span class="o">.</span><span class="n">exists</span><span class="p">({</span><span class="s">'filename'</span><span class="p">:</span> <span class="s">'file.txt'</span><span class="p">})</span> <span class="c"># equivalent to above</span>
<span class="go">True</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="s">'The quick brown fox'</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="s">'typingtest.txt'</span><span class="p">)</span>
<span class="go">ObjectId('4fbfad74fb72f0971c00000e')</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">fs</span><span class="o">.</span><span class="n">get_last_version</span><span class="p">(</span><span class="s">'typingtest.txt'</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="go">'The quick brown fox'</span>
</pre></div>


<p>So that's the whirlwind tour of GridFS. I'd love to hear how you're using GridFS
in your project, or if you think it might be a good fit, so please drop me a line
in the comments.</p><div class="blogger-post-footer"><!-- // MAILCHIMP SUBSCRIBE CODE \\ -->
<a href="http://eepurl.com/ifqEc">Subscribe to our newsletter</a>
<!-- \\ MAILCHIMP SUBSCRIBE CODE // --><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/18508356-7482087188291653420?l=blog.pythonisito.com" alt="" /></div>
<p><a href="http://feedads.g.doubleclick.net/~a/vGA0bf5qgbtr7HO5B8VCI1rWil8/0/da"><img src="http://feedads.g.doubleclick.net/~a/vGA0bf5qgbtr7HO5B8VCI1rWil8/0/di" border="0" ismap="true" /></a><br />
<a href="http://feedads.g.doubleclick.net/~a/vGA0bf5qgbtr7HO5B8VCI1rWil8/1/da"><img src="http://feedads.g.doubleclick.net/~a/vGA0bf5qgbtr7HO5B8VCI1rWil8/1/di" border="0" ismap="true" /></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=UQSk4aNLYVg:uidoFEyg1OA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=yIl2AUoC8zA" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=UQSk4aNLYVg:uidoFEyg1OA:4cEx4HpKnUU"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=UQSk4aNLYVg:uidoFEyg1OA:4cEx4HpKnUU" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=UQSk4aNLYVg:uidoFEyg1OA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=UQSk4aNLYVg:uidoFEyg1OA:F7zBnMyn0Lo" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=UQSk4aNLYVg:uidoFEyg1OA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=qj6IDK7rITs" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=UQSk4aNLYVg:uidoFEyg1OA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=UQSk4aNLYVg:uidoFEyg1OA:gIN9vFwOqvQ" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=UQSk4aNLYVg:uidoFEyg1OA:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=TzevzKxY174" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=UQSk4aNLYVg:uidoFEyg1OA:l6gmwiTKsz0"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?d=l6gmwiTKsz0" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/JustALittlePython?a=UQSk4aNLYVg:uidoFEyg1OA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/JustALittlePython?i=UQSk4aNLYVg:uidoFEyg1OA:V_sGLiPBpWU" border="0" /></a>
</div><img src="http://feeds.feedburner.com/~r/JustALittlePython/~4/UQSk4aNLYVg" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/JustALittlePython/~3/UQSk4aNLYVg/gridfs-mongodb-filesystem.html]]></link>
    <pubDate>2012-05-25 15:08:32</pubDate>
  </item>
  <item>
    <title><![CDATA[Mike Driscoll: Weekly Python Links Roundup Resurrected!]]></title>
    <description><![CDATA[<p>I haven&#8217;t done a weekly round-up of Python links because no one seemed to really care when I was doing those. However I thought I&#8217;d give it one more try and see if there was any interest this time around. This past week, I finished reading my first <a href="http://www.blog.pythonlibrary.org/2012/05/25/book-review-web2py-application-development-cookbook/" target="_blank">web2py cookbook</a>. I&#8217;m told there&#8217;s another book too, but I haven&#8217;t checked it out yet. I suspect had I read the other one first, the cookbook would have made more sense. If you&#8217;ve been a regular reader of this site, you&#8217;ll notice I&#8217;ve done several other book reviews the last couple of weeks too. Speaking of reading, here are just a few of the articles that stuck out to me this week:</p>
<ul>
<li>Logsna – a sane log output format (Ruslan Spivak&#8217;s <a href="http://ruslanspivak.com/2012/05/20/logsna-a-sane-log-output-format/" target="_blank">blog</a>)</li>
<li><a href="http://jessenoller.com/2012/05/23/python-org-redesign-request-for-proposals/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+Jessenollercom+%28jessenoller.com%29" target="_blank">Python.org Redesign Request For Proposals</a> (Jesse Noller)</li>
<li><a href="http://simeonfranklin.com/blog/2012/may/22/what-generators-are-for/" target="_blank">What Generators are for</a> (Simeon Franklin)
<li><a href="http://blog.python.org/2012/05/recent-windows-changes-in-python-33.html" target="_blank">Recent Windows Changes in Python 3.3 </a></li>
<li>I think it&#8217;s exciting that there&#8217;s now an <a href="http://pyfound.blogspot.com/2012/05/request-for-proposal-redesign-pythonorg.html" target="_blank">RFP out</a> for a redesign of the Python website</li>
<li>Nick Coghlan had a pretty <a href="http://www.boredomandlaziness.org/2012/05/embarrassment-of-riches.html" target="_blank">interesting article</a> about all the resources there are now for deployment, docs and testing</li>
</li></ul>
<p>I don&#8217;t want to overload you on links and I know this one is older, but I have been really interesting in following <a href="http://therealkatie.net/blog/2012/apr/30/pygame-returning-combat/" target="_blank">Katie C&#8217;s gaming adventures</a>. So I&#8217;ll leave you on that note. I hope you enjoy the articles as much as I did.</p>]]></description>
    <link><![CDATA[http://www.blog.pythonlibrary.org/2012/05/25/weekly-python-links-roundup-resurrected/]]></link>
    <pubDate>2012-05-25 14:38:24</pubDate>
  </item>
  <item>
    <title><![CDATA[Mike Driscoll: Book Review: web2py Application Development Cookbook]]></title>
    <description><![CDATA[<p>I have read about web2py on several occasions, but never used it myself. Then a few weeks ago, a representative from Packt Publishing contacted me about reviewing their new <a href="http://www.amazon.com/gp/product/1849515468/ref=as_li_ss_tl?ie=UTF8&tag=thmovsthpy-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=1849515468" target="_blank" rel="nofollow">cookbook </a>about web2py. It&#8217;s written by seven authors, namely: Richard Gordon, Pablo Martin Mulone, Mariano Reingart, Bruno Cezar Rocha, Massimo Di Pierro, Michele Comitini and Jonathan Lundell. I have to admit that I wondered how you could have a coherent book with so many authors, but since it&#8217;s a cookbook, it works out pretty well.<span id="more-2370"></span></p>
<h3>Quick Review</h3>
<ul>
<li><strong>Why I picked it up:</strong> Partly because Packt offered me a review copy and partially because I wanted to see how web2py differed from django and TurboGears</li>
<li><strong>Why I finished it:</strong> I finished it out of duty to the publisher and my audience. Cookbooks are hard to read straight through and tend to be kind of boring. </li>
<li><strong>I’d give it to:</strong> Beginner to intermediate developers wanting to learn some new tricks with web2py</li>
</ul>
<h3>Book Formats</h3>
<p>Paperback, Kindle (mobi) or PDF and epub (from Packt)</p>
<h3>Book Contents</h3>
<p>Chapter 1 is about deploying web2py to various backends. While a little dull, I think this section could be very helpful for deployment. The second chapter is mostly about improving on the &#8220;scaffolds&#8221; application that comes with web2py. Chapter 3 covers how web2py interacts with databases and various CSV manipulations. Number four covers advanced forms such as multiple forms on one page. I don&#8217;t find javascript very interesting right now, so chapter 5&#8242;s topic of AJAX didn&#8217;t do much for me. Chapter 6 covers some third party libraries, like Twitter connectivity, customizing logging, etc. In 7 we learn about web services and in 8 we go over authentication and authorization techniques. Chapter 9 is all about custom URL routing. For 10, we learn various ways to create PDF reports. The last chapter is a collection of recipes that didn&#8217;t really fit anywhere else and are pretty random. From PDB integration to using web2py with wxPython, it covers a wide array of topics.</p>
<h3>Review</h3>
<p>We&#8217;ll start off with some of the bad as I like to finish with the good. I found lots of silly issues that a normal spell check program should have flagged. The writing isn&#8217;t compelling either, but most cookbooks I&#8217;ve read are that way. It may be dry, but it does a decent job of explaining most of the recipes. Some are explained more than others. This is also pretty standard in a cookbook. I&#8217;m not knocking the authors for the poor editing as that&#8217;s not their job and I can tell that several if not all are not native English speakers. I&#8217;m sure they did their best. </p>
<p>What I liked most is that this book actually has recipes that I not only thought were interesting but that I could see myself actually using. There are recipes for integrating PayPal payments, creating CAPTCHAs, building Facebook and Reddit clones, various web service consumer recipes, and some debugging stuff at the end. I was especially interested in the PayPal stuff as I just haven&#8217;t seen much in the Python web framework world about payment systems in general.</p>
<p>The PDF integration was also interesting in that web2py can use reportlab, LaTeX or pyfpdf. I&#8217;d never heard of the last one, so that was interesting in and of itself. There really isn&#8217;t the space to go over all the recipes that caught my eye. I will point out that most of the examples are incomplete, probably because there just isn&#8217;t space. Fortunately you can download the full source code from Packt&#8217;s website. I should also note that some chapters seem to have more javascript than Python. That may be expected, but I was still a little surprised by it. Because the code is incomplete, I didn&#8217;t try to run it from the book. I don&#8217;t really recommend that anyway when it&#8217;s not all there.</p>
<p>Developers who would get the most out of this book are probably beginners to intermediate web2py programmers who would like to increase their skill set. I think there are lots of nifty tricks to be learned from this book and I hope to try them out at some point. </p>]]></description>
    <link><![CDATA[http://www.blog.pythonlibrary.org/2012/05/25/book-review-web2py-application-development-cookbook/]]></link>
    <pubDate>2012-05-25 12:35:17</pubDate>
  </item>
  <item>
    <title><![CDATA[Tarek Ziade: zmq and gevent debugging nightmares]]></title>
    <description><![CDATA[<img alt="http://powerhose.readthedocs.org/en/latest/_images/medium-powerhose.png" src="http://powerhose.readthedocs.org/en/latest/_images/medium-powerhose.png" />
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">Powerhose turns your CPU-bound tasks into I/O-bound tasks so your Python applications
are easier to scale.</p>
</div>
<p>I've released Powerhose 0.4 at PyPI - <a class="reference external" href="http://pypi.python.org/pypi/powerhose/0.4">http://pypi.python.org/pypi/powerhose/0.4</a>, and this
new version has a few changes that are worth speaking of.</p>
<div class="section" id="pyzmq-gevent">
<h2>pyzmq + gevent = ?</h2>
<p>The biggest issue I faced with Powerhose was related to gevent. We have a powerhose set up
here at Mozilla with 175 workers and each one of them is performing crypto work.</p>
<p>A Powerhose worker is just a call to <strong>powerhose-worker</strong> pointing to a callable.</p>
<p>What I did not realize was that the module that was imported was also used by our main
application, and was calling gevent and gevent_zmq monkey patching.</p>
<p><strong>gevent_zmq</strong> is a library that patches pyzmq so it interacts well with gevent. It's
going to die eventually since <em>pyzmq</em> is including a <em>green</em> module that will provide
gevent compatibility. But this module does not provide a Poller yet.</p>
<p>So, in other words, any project that has pyzmq &amp; gevent will <strong>block</strong> unless you
use gevent_zmq. And if you use the Poller you need my fork: <a class="reference external" href="https://github.com/tarekziade/gevent-zeromq">https://github.com/tarekziade/gevent-zeromq</a></p>
<p>Back to my workers. Having them patched by gevent/gevent_zmq is not an issue per se.
It can even speed up very slightly things since the workers are fetching certificates on
the web sometimes.</p>
<p>But at some point -- or more precisely, around every 24 hours, the workers were simply
locking themselve and hanging there.</p>
<p>After a lot of work, I found out that gevent had its own dns resolver which was used
when calling <strong>socket.getaddrinfo</strong>, and for some reason -- a bad interaction between zmq
and gevent I suspect, a greenlet was locked.</p>
<p>Maybe that's a bug in gevent_zmq, maybe that's an issue in gevent itself..</p>
<p>I failed to find the real reason because the lock happened in various places in the
gevent socket code. I did not spend more time on this since the bug seems to have gone
away once I removed gevent altogether from the workers as we don't use gevent there
and the workers are <strong>sync</strong> beasts.</p>
<p>The one thing I was able to do though was to write a little piece of code to
dump all running threads and greenlets to understand what's going on:</p>
<pre class="literal-block">
import traceback, sys, gc

def dump_stacks():
    dump = []

    # threads
    threads = dict([(th.ident, th.name)
                        for th in threading.enumerate()])

    for thread, frame in sys._current_frames().items():
        dump.append('Thread 0x%x (%s)\n' % (thread, threads[thread]))
        dump.append(''.join(traceback.format_stack(frame)))
        dump.append('\n')

    # greenlets
    try:
        from greenlet import greenlet
    except ImportError:
        return dump

    # if greenlet is present, let's dump each greenlet stack
    for ob in gc.get_objects():
        if not isinstance(ob, greenlet):
            continue
        if not ob:
            continue   # not running anymore or not started
        dump.append('Greenlet\n')
        dump.append(''.join(traceback.format_stack(ob.gr_frame)))
        dump.append('\n')

    return dump
</pre>
<p>That should be useful in the future.</p>
<p>Bottom line:</p>
<ul>
<li><p class="first">gevent does not have good debugging tools - I guess the function I wrote is
useful, it can be even injected live on a running process using Pyrasite.</p>
<p>But gevent should provide this kind of utility imho - I'll propose something</p>
</li>
<li><p class="first">I am looking forward for pyzmq.green with the Poll class. We've opened a ticket
on this, and it will eventually land I guess.</p>
</li>
</ul>
</div>
<div class="section" id="zmq-bind-bug">
<h2>zmq_bind() bug ?</h2>
<p>The other issue I had was with the ZMQ bind() API. Powerhose's Broker binds a
socket, but it turns out you can bind as many broker as you want on the
same IPC or TPC adress !</p>
<p>You end up with one active broker and a lot of <em>zombies brokers</em>...</p>
<p>See this bug to reproduce the issue:
<a class="reference external" href="https://github.com/zeromq/pyzmq/issues/209">https://github.com/zeromq/pyzmq/issues/209</a> (the past
scripts will be online for a month)</p>
<p>And that's the thread I started in the zmq mailing list:
<a class="reference external" href="http://lists.zeromq.org/pipermail/zeromq-dev/2012-May/017249.html">http://lists.zeromq.org/pipermail/zeromq-dev/2012-May/017249.html</a></p>
<p>So until this is solved, what I did is add a health feature in Powerhose.
You can now call the broker, but instead of passing a job, you can pass
a <strong>PING</strong> and the broker will directly return its PID instead of
passing your call to a worker.</p>
<p>That's good enough to make sure the broker is up and running, and
the <strong>powerhose-broker</strong> command line has gained two options:</p>
<pre class="literal-block">
$ powerhose-broker --check
.. checks if the broker is alive and running, prints its pids...

$ powerhose-broker --purge-ghosts
.. kill any &quot;ghost&quot; broker...
</pre>
<p>The broker itself does a --check when it starts and exits if it finds
a running broker on the same endpoint.</p>
<p>This will be useful for a Nagios checker. But... zmq should just error out
when you try to bind twice.</p>
<div class="section" id="what-s-next">
<h3>What's next</h3>
<p>I am wondering at this point, besides those small fixes, if Powerhose
should gain more features... Circus itself provides all the stats and
maintenances feature we need to manage powerhose workers..</p>
<p>Links:</p>
<ul class="simple">
<li>the doc: <a class="reference external" href="http://powerhose.readthedocs.org/en/latest/index.html">http://powerhose.readthedocs.org/en/latest/index.html</a></li>
<li>the release: <a class="reference external" href="http://pypi.python.org/pypi/powerhose/0.4">http://pypi.python.org/pypi/powerhose/0.4</a></li>
<li>the repo: <a class="reference external" href="https://github.com/mozilla-services/powerhose">https://github.com/mozilla-services/powerhose</a></li>
</ul>
<p>Please let us know what you think !</p>
</div>
</div>]]></description>
    <link><![CDATA[http://blog.ziade.org/2012/05/25/zmq-and-gevent-debugging-nightmares/]]></link>
    <pubDate>2012-05-25 11:29:00</pubDate>
  </item>
  <item>
    <title><![CDATA[Caktus Consulting Group: Narrowing the Gender Gap in the Open Source community]]></title>
    <description><![CDATA[<p>Diversity is important in a workplace environment. Having different points of view from people with different life experiences brings <a href="http://www.brighthub.com/office/human-resources/articles/90910.aspx">creative new ideas and innovative solutions</a> to the software development process. As a team of web developers that designs and builds custom web applications, creativity and gender diversity, I would argue, are closely tied and both crucial to the success of our projects.</p>
<p>Software development is traditionally a field dominated by men. The presence of women in programming is commanding more attention at conferences and events, particularly in recent years. There are many initiatives within the Python community to promote involvement, such as the group <a href="http://www.meetup.com/Women-Who-Code-SF/">Women Who Code</a>, and the long-term benefits of efforts like these cannot be overstated. At Caktus, three of the ten current members of our Django development staff are female, and we are actively working to further equalize the gender balance through future hires.</p>
<p>One part of closing the gender gap in programming communities involves creating a safe and inclusive environment for all parties, both in the workplace and at community events. This begins with strong employment policies on harassment &mdash; which we have implemented here at Caktus &mdash; and also extends to implementing policies at conferences or other events relevant to the development community. This blog post comes out of several recent events in the broader tech community that Caktus is a part of.  This includes two blog posts that drew a lot of attention, and two corporate events that demonstrated clearly for us how pervasive sexism still is in our industry.</p>
<p>In March, Katie Cunningham, a fellow Django developer and friend made through DjangoCon, wrote an excellent and widely read blog post titled &quot;<a href="http://therealkatie.net/blog/2012/mar/21/lighten-up/">Lighten Up</a>.&quot; The post details a story that is all too common in our industry, that of ongoing, but usually subtle sexist jokes and comments that serve only, whether intentionally or not, to gradually demoralize and discourage those to whom they are addressed. She discusses how the typical response, should someone get upset by such a &quot;joke&quot; or comment, is simply to &quot;lighten up&quot; and &quot;stop being so sensitive.&quot; I can see how that would get really old. Fast. In fact, just in reading up for writing this post, I was blown away by the number of comments in response to posts such as Katie's that fit exactly that description.</p>
<p>Just a couple weeks ago, the computer manufacturer Dell hosted a summit in Copenhagen. Dell hired a &quot;comedian&quot; to MC the event, who proceeded to entertain the attendees with <a href="http://news.cnet.com/8301-31322_3-57431869-256/why-we-need-to-keep-talking-about-women-in-tech/?tag=mncol;txt">a variety of sexist jokes</a>, acclaiming the &quot;success&quot; of the IT community as indicated by its male-dominated culture, and included a suggestion to the mostly male attendees that they go home and tell their partners to &quot;shut up bitch.&quot; Dell has finally put out <a href="https://plus.google.com/117161668189080869053/posts/5Zg5FdFEydi">an apology</a> about what happened, but the consensus seems to be that it's <a href="http://news.cnet.com/8301-31322_3-57434780-256/dell-apologizes-for-hiring-sexist-summit-moderator/">weak at best</a> and, given its tardiness, lost any sincerity it may once have had.</p>
<p>In closing, I&rsquo;d like to draw attention to one other aspect of the software development community, particularly at conferences, that often tends to aggravate any pre-existing sexism that might exist in the community. Last month, Ryan Funduk wrote an extensive and much-debated blog post, titled &quot;<a href="http://ryanfunduk.com/culture-of-exclusion/">Our Culture of Exclusion</a>,&quot; about the pervasiveness of drinking at many programming conferences. He also discusses how, all too often, these environments are ripe with sexist or racist jokes (or worse) that quickly erode any efforts to further diversify such communities. One example that he highlights is the daily deal API provider Sqoot, who alienated and offended many when they suggested that women are<a href="http://www.readwriteweb.com/enterprise/2012/03/how-casual-sexism-put-sqoot-in.php"> </a><a href="http://www.readwriteweb.com/enterprise/2012/03/how-casual-sexism-put-sqoot-in.php">better fit to serve beer than to program</a>. Sqoot made<a href="http://blog.sqoot.com/we-can-do-better-an-apology-from-sqoot"> </a><a href="http://blog.sqoot.com/we-can-do-better-an-apology-from-sqoot">several apologies</a> about this unfortunate advertisement, but many of them still fell short and only worsened the offense, as this response from<a href="https://twitter.com/#%21/gayle"> </a><a href="https://twitter.com/#%21/gayle">Gayle McDowell</a> aptly sums up:</p>
<blockquote>Your language, as far as I understand it, is making the assumption that all coders are male, that all are straight, that women are sexual objects offered as a reward (HIGHLY inappropriate in a professional context), and that the women are there to serve them.</blockquote>
<p>She goes on to suggest an appropriate response if and when events like this do happen:</p>
<blockquote>People screw up sometimes. It happens. A TON of people (both men and women) have done equally offensive things. // But when you do it, you need to own up to it and think about what you've done. Not lie about it, as you're doing now.</blockquote>
<p>Clearly, we need to have policies in place for handling instances of sexist or racist jokes and sexual harassment. When they do happen, McDowell says, one needs to take responsibility and own up to the mistakes one has made in an honest way.</p>
<p>The bar has been set, and I think it&rsquo;s worth noting that several lessons can be taken from these events and applied to our own communities. Caktus is a long-time sponsor of several conferences relevant to the work that we do. Along with this blog post, Caktus is asking conference organizers and other sponsors to join us in the following effort: Moving forward, Caktus will require that a <strong>zero-tolerance sexual harassment policy</strong> is established and <strong>enforced</strong> by the organizers of any conference that we sponsor or attend. We want to ensure that our community events are safe, welcoming, and supportive for all of our colleagues &mdash; both male and female. While drinking can certainly make things worse, it is not the root of the problem. To overcome these issues, we need to talk about them more, continue to raise awareness, and treat all people in our workplaces and communities with the professionalism and respect that they deserve.</p>]]></description>
    <link><![CDATA[http://www.caktusgroup.com/blog/2012/05/24/narrowing-gender-gap-open-source-community/]]></link>
    <pubDate>2012-05-24 20:44:57</pubDate>
  </item>
  <item>
    <title><![CDATA[Mike Driscoll: wxPython for Python 3 is Almost Here!!!]]></title>
    <description><![CDATA[<p>Robin Dunn, creator and mastermind behind wxPython, announced today on his <a href="http://wxpython.org/blog/2012/05/24/its-alive/" target="_blank">blog </a>and the <a href="https://groups.google.com/forum/?fromgroups#!topic/wxpython-dev/p5HQHZgT_XE" target="_blank">wxPython-dev mailing list</a> that he had gotten wxPython 2.9 (Phoenix) to build successfully for Python 3.2 on Mac. In fact, he posted a <a href="http://wxpython.org/Phoenix/ItsAlive/" target="_blank">Quicktime video</a> that shows the build and the tests running in Python 3! According to wxPython-dev, once they have some Python 3 buildbot slaves set up, then snapshot builds can be made and posted <a href="http://wxpython.org/Phoenix/snapshot-builds/">here</a>.</p>
<p>I&#8217;m pretty excited! Now if only the Python Imaging Library would convert too&#8230;</p>]]></description>
    <link><![CDATA[http://www.blog.pythonlibrary.org/2012/05/24/wxpython-for-python-3-is-almost-here/]]></link>
    <pubDate>2012-05-24 18:27:11</pubDate>
  </item>
  <item>
    <title><![CDATA[Robin Dunn: It’s Alive!]]></title>
    <description><![CDATA[<p>Watch as the Phoenix spreads her wings over Python 3:</p>
<p><a href="http://wxpython.org/Phoenix/ItsAlive/">http://wxpython.org/Phoenix/ItsAlive/</a></p>]]></description>
    <link><![CDATA[http://wxPython.org/blog/2012/05/24/its-alive/]]></link>
    <pubDate>2012-05-24 16:52:51</pubDate>
  </item>
  <item>
    <title><![CDATA[Kristján Valur: Zombieframes.  A gratuitous optimization?]]></title>
    <description><![CDATA[<p>Examing a recent crash case, I stumbled across this code in frameobject.c:</p>
<pre class="brush: c">
PyFrameObject *
PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
PyObject *locals)
...
if (code-&gt;co_zombieframe != NULL) {
f = code-&gt;co_zombieframe;
code-&gt;co_zombieframe = NULL;
_Py_NewReference((PyObject *)f);
assert(f-&gt;f_code == code);
}
</pre>
<p>Intrigued by the name, I examined the header where it is defined, code.h:</p>
<pre class="brush: c">
...
void *co_zombieframe; /* for optimization only (see frameobject.c) */
...
} PyCodeObject;
</pre>
<p>It turns out that for every PyCodeObject object that has been executed, a PyFrameObject of a suitable size is cached and kept with the code object. Now, caching is fine and good, but this cache is unbounded. Every code object has the potential to hang on to a frame, which may then never be released.<br />
Further, there is a separate freelist cache for PyFrameObjects already, in case a frame is not found on the code object:</p>
<pre class="brush: c">
if (free_list == NULL) {
f = PyObject_GC_NewVar(PyFrameObject, &amp;amp;PyFrame_Type,
extras);
if (f == NULL) {
Py_DECREF(builtins);
return NULL;
}
}
else {
assert(numfree &gt; 0);
--numfree;
f = free_list;
free_list = free_list-&gt;f_back;
...
</pre>
<p>Always concious about memory these days, I tried disabling this in version 3.3 and running the pybench test. I was not able to see any conclusive difference in execution speed.</p>
<h2>Update:</h2>
<p>Disabling the zombieframe on the PS3 shaved off some 50k on startup.  Not the jackpot, but still, small things add up.</p>
<blockquote><p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
PYBENCH 2.1<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
* using CPython 3.3.0a3+ (default, May 23 2012, 20:02:34) [MSC v.1600 64 bit (AMD64)]<br />
* disabled garbage collection<br />
* system check interval set to maximum: 2147483647<br />
* using timer: time.perf_counter<br />
* timer: resolution=2.9680909446810176e-07, implementation=QueryPerformanceCounter()</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Benchmark: nozombie<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>Rounds: 10<br />
Warp: 10<br />
Timer: time.perf_counter</p>
<p>Machine Details:<br />
Platform ID: Windows-7-6.1.7601-SP1<br />
Processor: Intel64 Family 6 Model 26 Stepping 5, GenuineIntel</p>
<p>Python:<br />
Implementation: CPython<br />
Executable: D:pydevhgcpython2pcbuildamd64python.exe<br />
Version: 3.3.0a3+<br />
Compiler: MSC v.1600 64 bit (AMD64)<br />
Bits: 64bit<br />
Build: May 23 2012 20:02:34 (#default)<br />
Unicode: UCS4</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Comparing with: zombie<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>Rounds: 10<br />
Warp: 10<br />
Timer: time.perf_counter</p>
<p>Machine Details:<br />
Platform ID: Windows-7-6.1.7601-SP1<br />
Processor: Intel64 Family 6 Model 26 Stepping 5, GenuineIntel</p>
<p>Python:<br />
Implementation: CPython<br />
Executable: D:pydevhgcpython2pcbuildamd64python.exe<br />
Version: 3.3.0a3+<br />
Compiler: MSC v.1600 64 bit (AMD64)<br />
Bits: 64bit<br />
Build: May 23 2012 20:00:42 (#default)<br />
Unicode: UCS4</p>
<p>Test minimum run-time average run-time<br />
this other diff this other diff<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
BuiltinFunctionCalls: 51ms 52ms -3.3% 52ms 53ms -2.0%<br />
BuiltinMethodLookup: 33ms 33ms +0.0% 34ms 34ms +0.8%<br />
CompareFloats: 50ms 50ms +0.1% 50ms 50ms +0.4%<br />
CompareFloatsIntegers: 99ms 98ms +0.8% 99ms 99ms +0.6%<br />
CompareIntegers: 77ms 77ms -0.5% 77ms 77ms -0.3%<br />
CompareInternedStrings: 60ms 60ms +0.0% 61ms 61ms -0.1%<br />
CompareLongs: 46ms 45ms +1.5% 46ms 45ms +1.2%<br />
CompareStrings: 61ms 59ms +3.6% 61ms 59ms +3.6%<br />
ComplexPythonFunctionCalls: 60ms 58ms +3.3% 60ms 58ms +3.2%<br />
ConcatStrings: 48ms 47ms +2.4% 48ms 47ms +2.1%<br />
CreateInstances: 58ms 57ms +1.3% 59ms 58ms +1.3%<br />
CreateNewInstances: 43ms 43ms +1.1% 44ms 44ms +1.1%<br />
CreateStringsWithConcat: 79ms 79ms -0.3% 79ms 79ms -0.1%<br />
DictCreation: 71ms 71ms +0.4% 72ms 72ms +1.0%<br />
DictWithFloatKeys: 72ms 70ms +2.1% 72ms 71ms +1.8%<br />
DictWithIntegerKeys: 46ms 46ms +0.7% 46ms 46ms +0.4%<br />
DictWithStringKeys: 41ms 41ms +0.0% 41ms 41ms -0.1%<br />
ForLoops: 35ms 37ms -4.0% 35ms 37ms -4.0%<br />
IfThenElse: 64ms 64ms -0.1% 64ms 64ms -0.4%<br />
ListSlicing: 49ms 50ms -1.0% 53ms 53ms -0.8%<br />
NestedForLoops: 54ms 51ms +6.7% 55ms 51ms +6.7%<br />
NestedListComprehensions: 54ms 54ms -0.7% 54ms 55ms -2.2%<br />
NormalClassAttribute: 94ms 94ms +0.1% 94ms 94ms +0.1%<br />
NormalInstanceAttribute: 54ms 54ms +0.3% 54ms 54ms +0.2%<br />
PythonFunctionCalls: 58ms 57ms +0.8% 58ms 58ms +0.6%<br />
PythonMethodCalls: 65ms 61ms +6.3% 66ms 62ms +5.9%<br />
Recursion: 84ms 85ms -1.0% 85ms 85ms -0.9%<br />
SecondImport: 74ms 76ms -2.5% 74ms 77ms -3.5%<br />
SecondPackageImport: 75ms 78ms -3.8% 76ms 79ms -3.9%<br />
SecondSubmoduleImport: 163ms 169ms -3.4% 164ms 170ms -3.3%<br />
SimpleComplexArithmetic: 43ms 43ms +1.0% 43ms 43ms +1.0%<br />
SimpleDictManipulation: 80ms 78ms +2.2% 81ms 79ms +2.4%<br />
SimpleFloatArithmetic: 42ms 42ms +0.1% 42ms 42ms -0.0%<br />
SimpleIntFloatArithmetic: 52ms 53ms -1.2% 52ms 53ms -1.1%<br />
SimpleIntegerArithmetic: 52ms 52ms -0.7% 52ms 53ms -0.8%<br />
SimpleListComprehensions: 45ms 45ms -0.2% 45ms 45ms +0.3%<br />
SimpleListManipulation: 44ms 46ms -4.0% 44ms 46ms -3.9%<br />
SimpleLongArithmetic: 32ms 32ms -0.9% 32ms 32ms -0.1%<br />
SmallLists: 58ms 57ms +1.2% 58ms 67ms -12.8%<br />
SmallTuples: 64ms 65ms -0.5% 65ms 65ms -0.2%<br />
SpecialClassAttribute: 148ms 149ms -0.8% 149ms 150ms -1.0%<br />
SpecialInstanceAttribute: 54ms 54ms +0.2% 54ms 54ms +0.0%<br />
StringMappings: 120ms 117ms +2.5% 120ms 117ms +2.5%<br />
StringPredicates: 62ms 62ms +0.9% 62ms 62ms +1.0%<br />
StringSlicing: 69ms 68ms +1.6% 69ms 68ms +2.1%<br />
TryExcept: 37ms 37ms +0.0% 37ms 37ms +0.5%<br />
TryFinally: 40ms 37ms +6.7% 40ms 37ms +6.5%<br />
TryRaiseExcept: 19ms 20ms -1.0% 20ms 20ms -0.4%<br />
TupleSlicing: 65ms 65ms +0.5% 66ms 65ms +1.2%<br />
WithFinally: 57ms 56ms +1.9% 57ms 56ms +2.1%<br />
WithRaiseExcept: 53ms 53ms +0.3% 54ms 54ms -0.8%<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Totals: 3154ms 3145ms +0.3% 3176ms 3177ms -0.0%</p>
<p>(this=nozombie, other=zombie)</p></blockquote>
<p>I&#8217;m going to remove this weird, unbounded cache from the python interpreter we use on the PS3.</p>]]></description>
    <link><![CDATA[http://blog.ccpgames.com/kristjan/2012/05/23/zombieframes-a-gratuitous-optimization/]]></link>
    <pubDate>2012-05-24 14:14:56</pubDate>
  </item>
  <item>
    <title><![CDATA[PyCon: PyCon DE 2012 - Registration Open]]></title>
    <description><![CDATA[We are glad to announce that the registration for the&nbsp;<a href="http://2012.de.pycon.org/">second PyCon DE</a>&nbsp;in Leipzig is open. You can now buy&nbsp;<a href="http://2012.de.pycon.org/tickets/">tickets </a>at the&nbsp;early-bird rate until end of June before prices will go up. Don't miss the opportunity to come the larges meeting of the German-speaking Python community and secure your ticket now.<br /><br />If you plan not only to come but also to&nbsp;contribute, you can <a href="http://2012.de.pycon.org/proposals/submit/">submit</a> a proposal for a talk or a tutorial. A wide&nbsp;variety&nbsp;of Python-related&nbsp;topics are&nbsp;welcome. More details in an&nbsp;<a href="http://pycon.blogspot.de/2012/05/pycon-de-2012-call-for-proposals-for.html">earlier post</a>.<br /><br />The&nbsp;<a href="http://2012.de.pycon.org/">second PyCon DE</a>&nbsp;will be in Leipzig from October 29 through November 3, 2012. One tutorial day, three days with talks and two days with a barcamp, code retreat &nbsp;and sprints will provide different ways to communicate about Python. There will be social events to give everybody ample opportunity to network with like-minded Pythonistas.<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/11638628-6418397215610179535?l=pycon.blogspot.com" alt="" /></div>]]></description>
    <link><![CDATA[http://pycon.blogspot.com/2012/05/pycon-de-2012-registration-open.html]]></link>
    <pubDate>2012-05-24 13:09:02</pubDate>
  </item>
  <item>
    <title><![CDATA[Python Insider: Recent Windows Changes in Python 3.3]]></title>
    <description><![CDATA[<div class="document" id="recent-windows-changes-in-python-3-3">
The Windows build of Python 3.3 has recently seen changes that could use a look from the community throughout our alpha and beta cycle. The first change is the long requested addition of Python to the system <tt class="docutils literal">Path</tt> variable, which was completed in the installer. Secondly, the build was upgraded to Visual Studio 2010.<br />
<br />
<div class="section" id="python-on-the-path">
<h4>


Python on the Path</h4>
A long requested feature, especially from beginners to those involved in education and training, has been the ability for the Python installer to place itself in the system <tt class="docutils literal">Path</tt> environment variable. Having the following message appear when you try to run a simple exercise is not a great first experience:<br />
<blockquote>
<tt class="docutils literal">'python' is not recognized as an internal or external command, operable program or batch file.</tt></blockquote>
Because of that, the first post-install step by many users is to edit the <tt class="docutils literal">Path</tt> environment variable manually to insert the C:Python33 directory. This allows the user to simply type <tt class="docutils literal">python</tt> on the command line and have it open <tt class="docutils literal"><span class="pre">C:\\Python33\\python.exe</span></tt> -- a very desirable feature for a majority of users. In fact, it's such a common post-install step that there are a huge amount of tutorials either about this step by itself or tutorials where their setup introduces this step before moving on.<br />
<blockquote>
<img alt="http://i.imgur.com/aixuY.png" src="http://i.imgur.com/aixuY.png" />
</blockquote>
The easiest part of the whole thing was <a class="reference external" href="http://hg.python.org/cpython/rev/4e9f1017355f">the code</a>. <tt class="docutils literal">Path</tt> manipulation in the installer consists of adding a new feature to the Feature table, then the Environment table may be updated based on selection of the Path feature. If the feature was selected, the Environment table is modified in a way that the <tt class="docutils literal">Path</tt> is prepended to and will be correctly cleaned up on uninstallation.<br />
<br />
The harder part was deciding how to go about the change. If you're going to provide <tt class="docutils literal">Path</tt> manipulation, the major questions are to do it by default or not, and to prepend or append to the <tt class="docutils literal">Path</tt>.<br />
<br />
We decided that it wasn't appropriate to make this a default feature. For one, in the dual-version state many users are running in, we run the risk of users running through the installer and putting their system into a state they aren't prepared for. We don't want to change the meaning of <tt class="docutils literal">python</tt> when executed on the command line without the user asking for it. On one hand it's a very beginner focused feature in that it gets a first-timer successfully up and running with ease. However, it's also an advanced feature in that it takes a good understanding of what it's going to do to the users who have 2.6, 2.7, 3.2, and now 3.3 on their machines. We think the best solution for all is to leave it up to them and include an explanation.<br />
<br />
The other part we had to think about was whether to prepend or append to the path. While some believe that appending to the path is the more friendly way to work with the system, it would seem to be of limited utility given that the feature is added this late in the game. Instead we went the route of prepending the installation folder, e.g., C:\Python33, in order to make sure this feature is actually useful to our users.<br />
<br />
If you have questions or comments, please feel free to raise them on python-dev or see  <a class="reference external" href="http://bugs.python.org/issue3561">Issue 3561</a>.<br />
<br /></div>
<div class="section" id="transition-to-visual-studio-2010">
<h4>


Transition to Visual Studio 2010</h4>
In time for the last alpha release, we've updated our build tools from Visual Studio 2008 to 2010.<br />
Many potential contributors as well as general Python users have long moved to work environments that use Visual Studio 2010. During a "bug day" some months ago, we had two or three patches come from interested first-timers who found our VS2008 solution not working in VS2010. Over time we received a few more contributions and bug reports on the topic, as well as some chatter in IRC about being behind the curve.<br />
<br />
On top of that, my employer at the time moved to VS2010 as well as the employers of at least one other core maintainer, so we were already operating on ports for our companies.<br />
<br />
When it came time to think about what to do for Python 3.3, moving to VS2010 became a <em>must have</em> due to our release schedule. Staying with VS2008 for 3.3 would put us into the middle of 2014 as the next time we could release on a new version. That would leave us at least two versions behind, with VS2010 as well as VS11 being available by then.<br />
<br />
Another reason is the relative ease of porting between VS2010 and VS11. Once we got ourselves on to 2010, moving on to 11 would not be that hard. VS11 currently reads our VS2010 files without change if you want to use the IDE features of VS11. However, there'd need to be another port in order to use the VS11 compiler suite, but it seems to require minimal effort. Just following the VS11 wizard produced a functioning executable, although it didn't build cleanly.<br />
<br />
<div class="section" id="where-to-get-visual-studio-2010">
<h5>


Where to get Visual Studio 2010?</h5>
As usual, Microsoft provides a zero-cost version of Visual Studio 2010 in the name Visual C++ Express, available at <a class="reference external" href="http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express">http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express</a>. While there are <a class="reference external" href="http://msdn.microsoft.com/en-us/library/hs24szh9(v=vs.100).aspx">some differences</a> between the Express version and the for-purchase versions, the Express version is used successfully by many contributors.<br />
<br />
The fine folks at Microsoft's <a class="reference external" href="http://www.microsoft.com/en-us/openness/default.aspx#home">Open Source Technology Center</a> have provided the core contributors with MSDN licenses free of charge, allowing for access to the full versions of Visual Studio among other products. The full versions of Visual Studio support 64-bit compilation which comes in handy for our amd64 releases, which have been available since 2.5.<br />
<br /></div>
</div>
<div class="section" id="help-us-out-try-the-alphas-and-betas">
<h4>


Help us out -- try the alphas and betas!</h4>
With a change to the installer, a new build system, and the <a class="reference external" href="http://docs.python.org/dev/whatsnew/3.3.html">other great changes</a> we have in store, the more feedback we hear from the community during the development cycle, the better we can make this release. If you have a chance to run your projects on Python 3.3, <a class="reference external" href="http://bugs.python.org/">http://bugs.python.org</a> is always open for your reports. You've even got a month to get feature requests in and completed!<br />
<br />
The last alpha release is scheduled for this weekend, and the first beta release is scheduled for June 24. You can download our 3.3.0 releases at <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">http://www.python.org/download/releases/3.3.0/</a>.</div>
</div><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/3941553907430899163-2117644518967524777?l=blog.python.org" alt="" /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:-BTjWOF_DHI" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:F7zBnMyn0Lo" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:V_sGLiPBpWU" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0" /></a>
</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/rWPwayEXWfE" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/PythonInsider/~3/rWPwayEXWfE/recent-windows-changes-in-python-33.html]]></link>
    <pubDate>2012-05-24 13:08:43</pubDate>
  </item>
  <item>
    <title><![CDATA[Python Software Foundation: 2012 Q1 Community Service Awards]]></title>
    <description><![CDATA[<div class="document" id="q1-community-service-awards">
The Foundation wishes to thank Carl Trachte and Audrey Roy for their work in the Python community with <a class="reference external" href="http://www.python.org/community/awards/psf-awards/">Community Service Awards</a> for the first quarter of 2012.<br />
<br />
Carl has put significant effort into diversifying and supporting non-English speaking writers for the Python Wiki.<br />
<br />
Audrey also put in a lot of time diversifying the community with her work in creating the PyLadies group as well speaking on outreach issues as numerous conferences.<br />
<br />
On behalf of the Python community, the PSF thanks Carl and Audrey for their time and effort!</div><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/8520-1810795452173646647?l=pyfound.blogspot.com" alt="" /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=g2PLacIMnXU:0NZqOv15ZNc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?d=yIl2AUoC8zA" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=g2PLacIMnXU:0NZqOv15ZNc:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=g2PLacIMnXU:0NZqOv15ZNc:-BTjWOF_DHI" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=g2PLacIMnXU:0NZqOv15ZNc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=g2PLacIMnXU:0NZqOv15ZNc:F7zBnMyn0Lo" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=g2PLacIMnXU:0NZqOv15ZNc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=g2PLacIMnXU:0NZqOv15ZNc:V_sGLiPBpWU" border="0" /></a>
</div><img src="http://feeds.feedburner.com/~r/PythonSoftwareFoundationNews/~4/g2PLacIMnXU" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/PythonSoftwareFoundationNews/~3/g2PLacIMnXU/2012-q1-community-service-awards.html]]></link>
    <pubDate>2012-05-24 10:30:04</pubDate>
  </item>
  <item>
    <title><![CDATA[Alex Clark: A simple printer of nested lists]]></title>
    <description><![CDATA[<p><em>A rant</em></p>
<p>Do you ever get the urge to kill? How many of us cringe whenever we see these words? Lately I&#8217;ve been spending a lot of time developing <a href="http://pythonpackages.com">pythonpackages.com</a>, (now running on heroku!) during which time I see a lot of these kinds of packages being released:</p>
<p><a href="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-9.41.32-PM.png"><img class="alignright size-full wp-image-4901" title="Screen Shot 2012-05-23 at 9.41.32 PM" src="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-9.41.32-PM.png" alt="" width="681" height="321" /></a></p>
<p>I kid about the killing part, but seriously: <strong>this is a problem</strong>. Fortunately for us, our PyPI overloads see fit to occasionally remove these packages, and for this I am grateful. I love seeing this:</p>
<p><a href="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-9.57.43-PM.png"><img class="alignright size-full wp-image-4905" title="Screen Shot 2012-05-23 at 9.57.43 PM" src="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-9.57.43-PM.png" alt="" width="1018" height="622" /></a></p>
<p>I mean it makes me <em>dance-around-the-room</em> happy! Ahem. But are they really all gone? Close enough. A quick <a href="https://crate.io/?q=a+simple+printer+of+nested+lists">crate.io search</a> now shows only 2 packages instead of 4 pages of results:</p>
<p><a href="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-10.04.46-PM.png"><img class="alignright size-full wp-image-4911" title="Screen Shot 2012-05-23 at 10.04.46 PM" src="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-10.04.46-PM.png" alt="" width="763" height="558" /></a></p>
<p>Hallelujah! But is this the best we can do? I know that some well-meaning person wrote a book containing the example that is leading some poor, misguided souls to spam PyPI (if only the author listed the test site instead: <a href="http://testpypi.python.org/pypi">http://testpypi.python.org/pypi</a>). And I have to assume that this was just some terrible mistake. But do we all have to live with this mistake?</p>
<p>I&#8217;m asking because I honestly don&#8217;t know the answer. I remember when I started pythonpackages.com, the <a href="http://pythonpackages.com/package/deliverance">Deliverance</a> documentation was being updated something like every 5 minutes (kidding again, but it was frequent enough to be annoying). After grousing about it in public, it stopped happening!</p>
<p>I wonder if some good natured grousing about our friends (read: enemies) the <em>simple printers of nested lists</em> will do the same?</p>
<img src="http://feeds.feedburner.com/~r/aclark/python/~4/qZ4IvG00EPs" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/aclark/python/~3/qZ4IvG00EPs/]]></link>
    <pubDate>2012-05-24 02:58:36</pubDate>
  </item>
  <item>
    <title><![CDATA[Mike Driscoll: My First Patch Was Accepted!]]></title>
    <description><![CDATA[<p>I&#8217;m a little excited today as my first patch (and first ticket even!) has been accepted. And it really didn&#8217;t take very long either. Less than 24 hours after I had submitted my first patch, I got my contribution added. I did have to submit to more variations of the patch though as my first one wasn&#8217;t quite right. I wanted to give a shout out to Brian Curtin and Eli Bendersky who helped me figure all this stuff out and made my first foray into core Python development a success. Personally, I think it would have been a success even if the patch wasn&#8217;t accepted as I still learned a lot along the way.</p>
<p>Things to take away from the experience:</p>
<ul>
<li>Try to stay on topic! I actually found a second issue with the paragraph I was fixing in the devguide and that probably should have gone in a separate bug report.</li>
<li>Number your patches! I don&#8217;t know why I didn&#8217;t think of that, but Eli told me I should do that in the future to make it less confusing for the committer. That was a face palm moment.</li>
</ul>
<p>I&#8217;ve been reading some of the supposedly &#8220;easy bugs&#8221; and trying to figure out where else I can help. I already spotted another typo in the docs that are included with Python itself which I&#8217;ll probably try to fix. Of course, I want to actually contribute to the code, not just the documentation, but I am probably more likely to be able to find documentation bugs I can help with. Hopefully with more experience I&#8217;ll be able to contribute more effectively. Happy hacking my fellow Pythoneers!</p>]]></description>
    <link><![CDATA[http://www.blog.pythonlibrary.org/2012/05/23/my-first-patch-was-accepted/]]></link>
    <pubDate>2012-05-24 00:29:02</pubDate>
  </item>
  <item>
    <title><![CDATA[Enthought: Just released! EPD 7.3 plus beta version of EPD 8.0]]></title>
    <description><![CDATA[Today we have for you not just one, but two exciting EPD releases &#8212; an update of EPD to 7.3 and a beta release previewing new features coming in EPD 8.0. The EPD 7.3 update adds several new packages including Shapely, openpyxl, and a new package from Enthought named EnaML.  EnaML is a new package for [...]]]></description>
    <link><![CDATA[http://blog.enthought.com/general/epd-73-and-8-beta/]]></link>
    <pubDate>2012-05-23 23:09:17</pubDate>
  </item>
  <item>
    <title><![CDATA[Python Software Foundation: Request for Proposal: Redesign python.org]]></title>
    <description><![CDATA[The main Python site at <a href="http://www.python.org/">www.python.org</a> was redesigned in 2005-2006 -- over six years ago.  It's time for a redesign, to improve the organization of the site and its appearance, and to simplify the task for the volunteers who maintain the content.  The PSF would therefore like fund the design and implementation of a new look and architecture for python.org.  The web development landscape has also changed a lot since 2006, and we look forward to seeing what this community can produce.<br />
<br />
The <a href="http://pythonorg-redesign.readthedocs.org/en/latest/index.html">Request for Proposal for the python.org redesign</a> has been published on readthedocs.org.  Questions and comments can be e-mailed to the psf-redesign mailing list at <a href="mailto:psf-redesign@python.org">psf-redesign at python.org</a>.  Proposals are due by July 21st 2012, two months from today.<br />
<br />
The RFP was initially drafted by Jesse Noller, and feedback from the python.org site maintainers was incorporated by Andrew Kuchling.<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/8520-5224525244093085722?l=pyfound.blogspot.com" alt="" /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=WBORCVywrHg:_paqNXBaExU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?d=yIl2AUoC8zA" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=WBORCVywrHg:_paqNXBaExU:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=WBORCVywrHg:_paqNXBaExU:-BTjWOF_DHI" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=WBORCVywrHg:_paqNXBaExU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=WBORCVywrHg:_paqNXBaExU:F7zBnMyn0Lo" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=WBORCVywrHg:_paqNXBaExU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=WBORCVywrHg:_paqNXBaExU:V_sGLiPBpWU" border="0" /></a>
</div><img src="http://feeds.feedburner.com/~r/PythonSoftwareFoundationNews/~4/WBORCVywrHg" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/PythonSoftwareFoundationNews/~3/WBORCVywrHg/request-for-proposal-redesign-pythonorg.html]]></link>
    <pubDate>2012-05-23 17:21:37</pubDate>
  </item>
  <item>
    <title><![CDATA[Shannon -jj Behrens: Async: To Be or Not To Be]]></title>
    <description><![CDATA[<div dir="ltr"><p>Just because I have to use a callback-oriented style on the client doesn't mean I want to use a callback-oriented style on the server.  Now, before anyone gets all upset and tells me that I don't know the difference between async and a kitchen sink, let me explain :)</p> <p>The client is necessarily an event-oriented place.  If I don't know which button the user is going to press, it makes a lot of sense to use a different callback for each button.  The server is different.  If I'm waiting for the result of a database query before I can continue processing a request, it sure is convenient to just block and wait.</p> <p>My key point is that it's important to separate what <i>style</i> you want to code with and what <i>performance and scalability characteristics</i> you want.  You shouldn't necessarily pick a callback-oriented style just because you want the performance and scalability characteristics of asynchronous networking APIs.</p> <p>My favorite two examples are gevent and Erlang, but Go is similar.  When you code using gevent or Erlang, your code looks like synchronous, blocking code.  However, below the covers, they use asynchronous networking APIs.  Now, before anyone tells me that it's impossible, buggy, or that it'll never work, let me point out that these tricks have been in production for decades at Ericsson, Yahoo Groups, and IronPort Cisco.</p> <p>Furthermore, I should point out that asynchronous networking APIs aren't a perfect fit for every problem.  For instance, if your goal is to send 10 gigabytes of information to another server, it turns out that synchronous networking APIs will actually outperform asynchronous networking APIs.  The reason asynchronous networking APIs are so popular is because they can handle a larger number of clients than synchronous networking APIs can and because they use less memory than a large number of threads, which each have to have their own stack.  gevent and Erlang can handle a large number of clients, don't use up much memory, and don't require a real OS-level stack per client.</p> <p>So what's my problem with the callback-oriented style?  I find it a lot harder to read.  I've coded projects in Twisted, Node.js, etc., and I prefer the gevent approach.  You get roughly the same performance and scalability characteristics, but with much easier to read code.  Of course, what's readable to me may not be readable to other people.  I've met people who are perfectly happy using Twisted Web 1 and don't think that callback-oriented code poses any real challenge.</p> <p>If you're interested in hearing more about my thoughts on async and concurrency, check out <a href="http://jjinux.blogspot.com/search?q=gevent+OR+concurrency">my other blog posts</a>, which include a link to my Dr. Dobb's Journal article on Python concurrency.</p></div><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/11788780-2537509446612004035?l=jjinux.blogspot.com" alt="" /></div>]]></description>
    <link><![CDATA[http://jjinux.blogspot.com/2012/05/async-to-be-or-not-to-be.html]]></link>
    <pubDate>2012-05-23 16:42:01</pubDate>
  </item>
  <item>
    <title><![CDATA[Jesse Noller: Python.org Redesign Request For Proposals]]></title>
    <description><![CDATA[<p>Well, it’s official — a labor of love from myself and many others — with special thanks to Andrew Kuchling for getting it over the finish line. The Python Software Foundation has officially announced a call for proposals for the redesign of the Python.org site and properties.</p>
<p>You can see the RFP here: <a href="http://pythonorg-redesign.readthedocs.org/en/latest/">http://pythonorg-redesign.readthedocs.org/en/latest/</a></p>
<p>It’s taken me several years of false starts, other attempts (including skunkworks attempts), political and social discussions, and the hard work of many to make this come to fruition. Now, we can only sit back and hope that we see some amazing proposals from the community and others.</p>
<p>I sincerely hope this will be successful, and that we will see a modern, well designed Python.org that showcases not only the language, but the vibrant, open, welcoming and active community we are all part of. </p>
 <p><a href="http://jessenoller.com/?flattrss_redirect&id=1141&md5=21a56dfa5feea14a76d208e81b851ac1" title="Flattr" target="_blank"><img src="http://jessenoller.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!" /></a></p>]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/Jessenollercom/~3/CJ1qZlQS29E/]]></link>
    <pubDate>2012-05-23 12:42:35</pubDate>
  </item>
  <item>
    <title><![CDATA[Python Diary: Starting to like Web2Py]]></title>
    <description><![CDATA[<p>I am starting to enjoy working with <a href="http://www.pythondiary.com/packages/web2py.html">Web2py</a><a href="http://web2py.com/" rel="tooltip" title="Direct link"><i class="icon-bookmark"></i></a>.  I was recently provided with a review copy of a recent Web2Py book, and I have started reading through it.  I will have a full review of this book in the next couple weeks.  When I first went on to learn Web2Py, I used the free online book, and that for the most part didn't change me over.  The free online, like <a href="http://www.pythondiary.com/packages/django.html">Django</a><a href="https://www.djangoproject.com/" rel="tooltip" title="Direct link"><i class="icon-bookmark"></i></a>'s online book, is just that.  A free online book, and didn't provide me with enough knowledge and confidence to develop using the framework.  I got into Django using it's very extensive documentation website.</p>
<p>The book I am reviewing has many examples which can easily be applied to real-world web applications, which I praise.  As I have been reading through the book, I have also been playing around and exploring Web2Py in general.  It has some very interesting design choices and features.  It is definitely good for someone who can never remember what to import, as there is rarely any need to import anything in web2py, besides when you need to import a 3rd party Python module.  At first, this design choice caught me off guard, as in Python, I am used to explicitly importing my modules for use.  Web2Py includes it's technical reference with the application itself, in the form of <a href="http://www.pythondiary.com/packages/epydoc.html">Epydoc</a><a href="http://epydoc.sourceforge.net/" rel="tooltip" title="Direct link"><i class="icon-bookmark"></i></a>.  I am not terribly fond of this documentation format, but it is how I learned <a href="http://www.pythondiary.com/packages/pyjamas.html">Pyjamas</a><a href="http://pyjs.org/" rel="tooltip" title="Direct link"><i class="icon-bookmark"></i></a>, as it uses the same documentation system.</p>
<p>Web2Py has some interesting magic, which frankly does make web development a breeze.  Generating forms and cruds is literally a one-liner, further customization can be made by using more lines of code.  Web2Py also comes with a nice default template, and the application wizard, has many additional templates for use as well.  This feature is definitely well welcomed in my book.  Sure, it implies that tons of websites made with Web2Py will have the same look and feel, but is that such a bad thing?  It just means that visitors will know where most resources can be found, and how to use the included form widgets.  Think of Wordpress, most Wordpress sites I visit keep the included wordpress theme.  Blogspot is another example of a set of websites which share a common theme.  The included themes allow one to get to developing the website as quickly as possible without having to worry about how it will look and feel, but rather focus on the functionality.  I am more of a functionality person, not a look-and-feel type of person.</p>
<p>All in all, I am very excited to be trying out Web2Py for a second time, and do hope that when I complete this book, I can both provide a review of the book itself, as well as the framework in general.  Neither of these reviews will be compared to anything, and be strictly of the book and framework itself.  I am thinking of making a future website using Web2Py to see where it goes.  I will most likely keep my blog running on Django, as I have used many Django-specific features which would be otherwise troublesome to migrate over.  These articles contain Django template code, for example.</p>]]></description>
    <link><![CDATA[http://www.pythondiary.com/blog/May.23,2012/starting-web2py.html]]></link>
    <pubDate>2012-05-23 11:42:19</pubDate>
  </item>
  <item>
    <title><![CDATA[Daniel Greenfeld: Django Class Based View: email form with CAPTCHA]]></title>
    <description><![CDATA[<p><a class="reference external" href="http://pydanny.com/simple-django-email-form-using-cbv.html">Yesterday I showed how to implement a simple email form</a> for <a class="reference external" href="http://djangoproject.com">Django</a> using Class Based Views. Today I'm going to extend yesterday's work to use the excellent <a class="reference external" href="http://www.google.com/recaptcha">RECAPTCHA</a> service to help reduce spam content.</p>
<p>This version requires <tt class="docutils literal">pip</tt> installing the following into your <tt class="docutils literal">virtualenv</tt>.</p>
<ul class="simple">
<li><tt class="docutils literal">pip install <span class="pre">django-crispy-forms</span></tt> so we can do Python driven layouts.</li>
<li><tt class="docutils literal">pip install <span class="pre">django-floppyforms</span></tt> so we get HTML5 elements for free.</li>
<li><tt class="docutils literal">pip install <span class="pre">django-recaptcha</span></tt> to do the RECAPTCHA work.</li>
</ul>
<p>Don't forget to add the app to your INSTALLED_APPS in settings.py:</p>
<div class="highlight"><pre><span class="n">INSTALLED_APPS</span> <span class="o">+=</span> <span class="p">(</span>
    <span class="s">'crispy_forms'</span><span class="p">,</span>
    <span class="s">'floppyforms'</span><span class="p">,</span>
    <span class="s">'captcha'</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>Generate your KEYs from the RECAPTCHA site and add them in settings.py:</p>
<div class="highlight"><pre><span class="n">RECAPTCHA_PUBLIC_KEY</span> <span class="o">=</span> <span class="s">'6LcVu9ESAAAAANVWwbM5-PLuLES94GQ2bIYmSNTG'</span>
<span class="n">RECAPTCHA_PRIVATE_KEY</span> <span class="o">=</span> <span class="s">'6LcVu9ESAAAAAGxz7aEIACWRa3CVnXN3mFd-cajP'</span>
</pre></div>
<p>In myapp.forms.py:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">captcha.fields</span> <span class="kn">import</span> <span class="n">ReCaptchaField</span>  <span class="c"># Only import different from yesterday</span>
<span class="kn">from</span> <span class="nn">crispy_forms.helper</span> <span class="kn">import</span> <span class="n">FormHelper</span>
<span class="kn">from</span> <span class="nn">crispy_forms.layout</span> <span class="kn">import</span> <span class="n">Submit</span>
<span class="kn">import</span> <span class="nn">floppyforms</span> <span class="kn">as</span> <span class="nn">forms</span>

<span class="k">class</span> <span class="nc">ContactForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>

    <span class="n">name</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">email</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">EmailField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">subject</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">message</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">Textarea</span><span class="p">)</span>
    <span class="n">captcha</span> <span class="o">=</span> <span class="n">ReCaptchaField</span><span class="p">()</span>  <span class="c"># Only field different from yesterday</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">helper</span> <span class="o">=</span> <span class="n">FormHelper</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">helper</span><span class="o">.</span><span class="n">add_input</span><span class="p">(</span><span class="n">Submit</span><span class="p">(</span><span class="s">'submit'</span><span class="p">,</span> <span class="s">'Submit'</span><span class="p">))</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">ContactForm</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
<p>In myapp.views.py:</p>
<div class="highlight"><pre><span class="c"># Unchanged from yesterday. :-)</span>
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.core.mail</span> <span class="kn">import</span> <span class="n">send_mail</span>
<span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">FormView</span>

<span class="kn">from</span> <span class="nn">myapp.forms</span> <span class="kn">import</span> <span class="n">ContactForm</span>

<span class="k">class</span> <span class="nc">ContactFormView</span><span class="p">(</span><span class="n">FormView</span><span class="p">):</span>

    <span class="n">form_class</span> <span class="o">=</span> <span class="n">ContactForm</span>
    <span class="n">template_name</span> <span class="o">=</span> <span class="s">&quot;myapp/email_form.html&quot;</span>
    <span class="n">success_url</span> <span class="o">=</span> <span class="s">'/email-sent/'</span>

    <span class="k">def</span> <span class="nf">form_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">form</span><span class="p">):</span>
        <span class="n">message</span> <span class="o">=</span> <span class="s">&quot;{name} / {email} said: &quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
            <span class="n">name</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'name'</span><span class="p">),</span>
            <span class="n">email</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'email'</span><span class="p">))</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="s">&quot;</span><span class="se">\n\n</span><span class="s">{0}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'message'</span><span class="p">))</span>
        <span class="n">send_mail</span><span class="p">(</span>
            <span class="n">subject</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'subject'</span><span class="p">),</span>
            <span class="n">message</span><span class="o">=</span><span class="n">message</span><span class="p">,</span>
            <span class="n">from_email</span><span class="o">=</span><span class="s">'contact-form@myapp.com'</span><span class="p">,</span>
            <span class="n">recipient_list</span><span class="o">=</span><span class="p">[</span><span class="n">settings</span><span class="o">.</span><span class="n">LIST_OF_EMAIL_RECIPIENTS</span><span class="p">],</span>
        <span class="p">)</span>
        <span class="k">return</span> <span class="nb">super</span><span class="p">(</span><span class="n">ContactFormView</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">form_valid</span><span class="p">(</span><span class="n">form</span><span class="p">)</span>
</pre></div>
<p>In templates/myapp/email_form.html:</p>
<div class="highlight"><pre>{# Also unchanged from yesterday. :-)  #}
{% extends 'base.html' %}
{% load crispy_forms_tags %}

{% block title %}Send an email{% endblock %}

{% block content %}
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;row&quot;</span><span class="nt">&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;span6&quot;</span><span class="nt">&gt;</span>
            <span class="nt">&lt;h1&gt;</span>Send an email<span class="nt">&lt;/h1&gt;</span>
            {% crispy form form.helper %}
        <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
{% endblock %}

{% block extrajs %}
<span class="nt">&lt;script </span><span class="na">src=</span><span class="s">&quot;{{ STATIC_URL }}js/jquery-1.7.1.min.js&quot;</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">&quot;text/javascript&quot;</span><span class="nt">&gt;</span>
<span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">$</span><span class="p">(</span><span class="s1">'#id_name'</span><span class="p">).</span><span class="nx">focus</span><span class="p">()</span>
<span class="p">});</span>
<span class="nt">&lt;/script&gt;</span>
{% endblock %}
</pre></div>
<div class="section" id="what-i-did">
<h2>What I did</h2>
<ul class="simple">
<li>Using <tt class="docutils literal">pip</tt> I installed three packages into my Python environment.</li>
<li>Added those three packages into the INSTALLED_APPS setting.</li>
<li>Set the RECAPTCHA keys for my site.</li>
<li>Modified the <tt class="docutils literal">forms.py</tt> file from yesterday to include the RECAPTCHA field.</li>
<li>Reduced spam content.</li>
</ul>
</div>
<div class="section" id="what-i-could-do">
<h2>What I could do</h2>
<ul class="simple">
<li>Pin the app versions for a particular release. This is what you should be doing in normal development and in production, but for a blog entry I'm avoiding it because release numbers become quickly dated.</li>
<li>Rather than change the <tt class="docutils literal">ContactForm</tt> from yesterday, I could have extended it via inheritance.</li>
</ul>
</div>
<div class="section" id="want-to-learn-more">
<h2>Want to learn more?</h2>
<p>If you live in the Los Angeles area and want to learn more about Django, everything from the basics to setting up a Content Management System or E-Commerce system, check out our Django (and <a class="reference external" href="http://python.org">Python</a>) training at <a class="reference external" href="https://academy.cartwheelweb.com">Cartwheel Academy</a>.</p>
</div>]]></description>
    <link><![CDATA[http://pydanny.com/django-class-based-view-email-form-with-captcha.html]]></link>
    <pubDate>2012-05-23 09:30:00</pubDate>
  </item>
  <item>
    <title><![CDATA[Mike Driscoll: Core Python Development: How to Submit a Patch]]></title>
    <description><![CDATA[<p>As I mentioned in my last article, I figured I&#8217;d try to find something that I could patch in Python and submit it. While writing the other article, I stumbled on a minor error in the Python devguide in the <a href="http://docs.python.org/devguide/setup.html#windows" target="_blank">Windows section</a>. While it&#8217;s nowhere near as cool to patch a piece of documentation as I think it would be to patch Python, I think it&#8217;s rather appropriate for me as I tend to contribute more documentation than anything else lately. So I am going to explain the process as I found it.<span id="more-2343"></span></p>
<h3>Getting Started</h3>
<p>First off, you need to get an account with the <a href="http://bugs.python.org/" target="_blank">Bug Tracker</a> for Python. If you hope to become a core developer, then you&#8217;ll need to make sure your username follows their guidelines, which are really simple:</p>
<p><code><br />
firstname.lastname<br />
</code></p>
<p>Once you&#8217;ve got that, you can start looking for something to patch. There&#8217;s a link that says &#8220;Easy issues&#8221; that is a good starting place. You can also do a search for a component that you&#8217;re competent in using and see if there are any bugs in there that you think you can fix. Once you find something, you&#8217;ll need to make sure you update your local repo and then read the devguide&#8217;s <a href="http://docs.python.org/devguide/patch.html" target="_blank">patch page</a>.</p>
<h3>Creating the Patch</h3>
<p>Assuming you have the necessary repository checked out on your local machine, all you need to do is go edit the appropriate file. In my case, I had to check out the devguide (which you can read about <a href="http://docs.python.org/devguide/" target="_blank">here</a>) and edit the <strong>setup.rst</strong> file. If you&#8217;re editing Python code, then you&#8217;ll have to conform to PEP8. Once I finished editing the file, I saved my changes and then had to use Mercurial to create the patch. Here&#8217;s the command I used per the Python<a href="http://docs.python.org/devguide/patch.html" target="_blank"> patch instructions</a>.</p>
<p><code><br />
hg diff &gt; setup.patch<br />
</code></p>
<p>And here is the contents of that patch file:</p>
<p><code><br />
diff -r b1c1d15271c0 setup.rst<br />
--- a/setup.rst	Tue May 22 00:33:42 2012 +0200<br />
+++ b/setup.rst	Tue May 22 13:55:09 2012 -0500<br />
@@ -173,7 +173,7 @@<br />
 To build from the Visual Studio GUI, open pcbuild.sln to load the project<br />
 files and choose the Build Solution option from the Build menu, often<br />
 associated with the F7 key. Make sure you have chosen the &quot;Debug&quot; option from<br />
-the build configuration drop-down first.<br />
+the configuration toolbar drop-down first.</code></p>
<p> Once built you might want to set Python as a startup project. Pressing F5 in<br />
 Visual Studio, or choosing Start Debugging from the Debug menu, will launch<br />
</p>
<p>Now that we have a patch we need to submit it!</p>
<h3>Submitting a Patch</h3>
<p>Put your shields up, we&#8217;re going in! Submitting a patch is a little daunting. What will people think of you? I suspect if you plan to work on something major, then you better start growing some thick skin. In my case, I&#8217;m going to submit a really simple typo fix, so I&#8217;m hoping that sort of thing isn&#8217;t flame-worthy. Then again, this is my first patch, so I may submit it in a completely erroneous way. Since my patch will be for something (presumably) new, I did a quick search to make sure it hadn&#8217;t already been reported. Seeing nothing, I clicked the &#8220;Create New&#8221; link with some trepidation and choose the &#8220;devguide&#8221; as my component. I also chose the latest version of Python. I don&#8217;t see anything in the devguide that says it applies to just one set of Python versions, so I&#8217;m just going to leave it at that. I didn&#8217;t really see a &#8220;type&#8221; that fit a devguide edit, so I left that blank for my betters to fix. Finally, I attached my patch file to the bug ticket. You can see my bug ticket <a href="http://bugs.python.org/issue14884">here</a> if you like.</p>
<p>When contributing a patch to Python, you should fill out a <a href="http://www.python.org/psf/contrib/" target="_blank">contributor agreement form</a> which allows the Python Software Foundation to license your code for use with Python while you get to keep the copyright. Yes, you too can become famous just for writing Python code! Assuming people read the source or those acknowledgement pages. </p>
<h3>Wrapping Up</h3>
<p>I don&#8217;t know what will happen to my rather lame contribution. Maybe it&#8217;ll get accepted, maybe not. But I think I&#8217;ll spend some time trying to figure out some other bugs and just see if there&#8217;s anything I can do to help out the Python community. Feel free to join me on this adventure!</p>]]></description>
    <link><![CDATA[http://www.blog.pythonlibrary.org/2012/05/22/core-python-development-how-to-submit-a-patch/]]></link>
    <pubDate>2012-05-22 23:22:07</pubDate>
  </item>
  <item>
    <title><![CDATA[Mikko Ohtamaa: Automatically colorize terminal tabs based on the server you are logged into]]></title>
    <description><![CDATA[<p>Behold:</p>
<p><img class="alignnone" title="Colorized tabs example scerenshot" src="https://github.com/downloads/miohtama/ztanesh/Screen%20Shot%202012-05-22%20at%2011.01.46%20PM.png" alt="" width="670" height="329" /></p>
<p>OSX&#8217;s <a href="http://opensourcehacker.com/category/python/feed/www.iterm2.com">iTerm 2</a>, and maybe some other terminal applications, support <a href="http://en.wikipedia.org/wiki/ANSI_escape_code">ANSI control sequence</a> extensions which allow shell to set the color of the terminal tab.</p>
<p>Below is a Python script which</p>
<ul>
<li>Randomizes a color based on the server host name. The same hostname always results to the same color.</li>
<li>The color is randomized in HSL color space, so that only the hue component varies and saturation and lightness are locked. This prevents the creation of ugly color combinations like black text on black tab background.</li>
</ul>
<p><em>Note: The effect can be also applied on terminal windows  &#8211; for those who don&#8217;t use tabs.</em></p>
<p>The effective result is that</p>
<ul>
<li>You learn to identify terminal tabs by the color</li>
<li>You can much more faster to switch between tabs, because you can visually pick up the terminal without needing to be able to read the text on it or remember its location in the list</li>
</ul>
<p><em>Note: If your puny terminal does not support setting the color of window decorations, you can always set the terminal background color. This is useful e.g. if you want to red background for <a href="http://www.youtube.com/watch?v=siwpn14IE7E&ob=av3n&noredirect=1">danger zone &#8482;</a> when you are logged in as root on the production server 23:00 Friday night.</em></p>
<p><em>Note: Naturally you also need to have the script installed on the servers you are ssh&#8217;ing into</em></p>
<h2>precmd() hook</h2>
<p>You can run the script once and the tab color is set. However, if you SSH from the computer to another  and then exit back, the color of the latest server would remain in this case.</p>
<p>This can be avoided by</p>
<ol>
<li>Calculating the OSC control code sequence needed to set the terminal tab color when the shell starts</li>
<li>Have a <em>precmd()</em> hook (zsh terminology, not sure what other shells use) to reset the tab color every time the shell prompt is displayd</li>
</ol>
<p>We, me with my friend, are maintaining (yet another) zsh toolkit called <a href="https://github.com/miohtama/ztanesh">ztanesh (github)</a>. There  you can find precmd() example codes in 1) <a href="https://github.com/miohtama/ztanesh/blob/master/zsh-scripts/rc/98-server-color">98-server-color</a> and 2) <a href="https://github.com/miohtama/ztanesh/blob/master/zsh-scripts/rc/99-prompt">80-statusbar</a>.</p>
<h2>rainbow-parade.py</h2>
<p><a href="https://github.com/miohtama/ztanesh/blob/master/zsh-scripts/bin/rainbow-parade.py">The script code lives on Github</a>. Currently it supports iTerm 2 only and we plan to expand support to Konsole. Patches for other terminals are welcome.</p>
<p>(This probably could be done in pure shell code too, but Python is just so much more fun&#8230;)</p>
<pre class="prettyprint lang-py">#!/usr/bin/env python
"""

       Set terminal tab / decoration color by the server name.

       Get a random colour which matches the server name and use it for the tab colour:
       the benefit is that each server gets a distinct color which you do not need
       to configure beforehand.

"""

import socket
import random
import colorsys
import sys

# http://stackoverflow.com/questions/1523427/python-what-is-the-common-header-format
__copyright__ = "Copyright 2012 Mikko Ohtamaa - http://opensourcehacker.com"
__author__ = "Mikko Ohtamaa &lt;mikko@opensourcehacker.com&gt;"
__licence__ = "WTFPL"
__credits__ = ["Antti Haapala"]

USAGE = """
Colorize terminal tab based on the current host name.

Usage: rainbow-parade.py [0-1.0] [0-1.0] # Lightness and saturation values

An iTerm 2 example (recolorize dark grey background and black text):

    rainbow-parade.py 0.7 0.4
"""

def get_random_by_string(s):
    """
    Get always the same 0...1 random number based on an arbitrary string
    """

    # Initialize random gen by server name hash
    random.seed(s)
    return random.random()

def decorate_terminal(color):
    """
    Set terminal tab / decoration color.

    Please note that iTerm 2 / Konsole have different control codes over this.
    Note sure what other terminals support this behavior.

    :param color: tuple of (r, g, b)
    """

    r, g, b = color

    # iTerm 2
    # http://www.iterm2.com/#/section/documentation/escape_codes"
    sys.stdout.write("\033]6;1;bg;red;brightness;%d\a" % int(r * 255))
    sys.stdout.write("\033]6;1;bg;green;brightness;%d\a" % int(g * 255))
    sys.stdout.write("\033]6;1;bg;blue;brightness;%d\a" % int(b * 255))
    sys.stdout.flush()

    # Konsole
    # TODO
    # http://meta.ath0.com/2006/05/24/unix-shell-games-with-kde/

def rainbow_unicorn(lightness, saturation):
    """
    Colorize terminal tab by your server name.

    Create a color in HSL space where lightness and saturation is locked, tune only hue by the server.

    http://games.adultswim.com/robot-unicorn-attack-twitchy-online-game.html
    """

    name = socket.gethostname()

    hue = get_random_by_string(name)

    color = colorsys.hls_to_rgb(hue, lightness, saturation)

    decorate_terminal(color)

def main():
    """
    From Toholampi with love http://www.toholampi.fi/tiedostot/119_yleisesite_englanti_naytto.pdf
    """
    if(len(sys.argv) &lt; 3):
        sys.exit(USAGE)

    lightness = float(sys.argv[1])
    saturation = float(sys.argv[2])

    rainbow_unicorn(lightness, saturation)

if __name__ == "__main__":
    main()</pre>
<p class="signature">
 <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="" /></a> <a href="http://feeds.feedburner.com/OpenSourceHacker" rel="alternate" type="application/rss+xml">Subscribe to this blog in a reader</a> <a href="http://twitter.com/moo9000"> <img valign="middle" src="http://opensourcehacker.com/wp-content/uploads/twitter-24.png" /></a> <a href="http://twitter.com/moo9000">Follow me on Twitter</a> </p>]]></description>
    <link><![CDATA[http://opensourcehacker.com/2012/05/22/automatically-colorize-terminal-tabs-based-on-the-server-you-are-logged-into/]]></link>
    <pubDate>2012-05-22 20:35:50</pubDate>
  </item>
  <item>
    <title><![CDATA[Simeon Franklin: What Generators are for]]></title>
    <description><![CDATA[<p>I teach Python classes and enjoy exploring language features from the
perspective of newbie's to the language. Usually I can explain the
rationale for Python language features by showing a compelling use
case. But what about generator functions?</p>


<a href="http://simeonfranklin.com/blog/2012/may/22/what-generators-are-for/">Read More</a>]]></description>
    <link><![CDATA[http://simeonfranklin.com/blog/2012/may/22/what-generators-are-for/]]></link>
    <pubDate>2012-05-22 17:57:51</pubDate>
  </item>
  <item>
    <title><![CDATA[Nick Coghlan: An embarrassment of riches]]></title>
    <description><![CDATA[Years ago (but still within the last decade) I was involved in a source control trade study for a large multi-national corporation. Management had let a non-software developer select the original "source control tool" and they had picked something that required custom scripting just to do a baseline (I wish I was kidding).<br /><br />So a bunch of candidate replacements were put forward for consideration, and CVS won because it was free, thus there would be fewer arguments with management about rolling it out on a project that was already over budget and behind schedule. (The fact that Subversion wasn't considered as a candidate should give you some additional hints about the precise timing of this - Subversion 1.0 was released in February 2004. Yes, for those that are new to this game, you read that right: it is only within the last decade that the majority of the open source VCS world began to enjoy the benefits of atomic commits).<br /><br />Other interesting aspects of that system included the fact that one of the developers on that project basically had to write a custom xUnit testing system from scratch in order to start putting together a decent automated test suite for the system, there was no code review tool, and you couldn't include direct links to bug tracker items in emails or anything else - you had to reference them by name or number, and people would then look those names or numbers up in the dedicated bug tracking application client.<br /><br />High level design documentation, if it existed at all, was in the form of Microsoft Word documents. Low level API documentation? Yes, that would have been nice (there were some attempts to generate something vaguely readable with Doxygen but, yeah, well, C++).<br /><br />Less than ten years later, though, and there are signs our industry is starting to grow up (although I expect many enterprise shops are still paying extortionate rates to the likes of IBM for the "Rational" suite of tools only to gain a significantly inferior development experience):<br /><ol><li>You can get genuinely high quality code hosting for free. Sure <a href="http://sourceforge.net/">Sourceforge</a> was already around back then, but Git and Mercurial stomp all over CVS from a collaboration point of view. These also come with decent issue trackers and various other collaboration tools. If you don't want to trust a service provider with your code, than tools like <a href="http://gitlabhq.com/">GitLab</a> let you set up similar environments internally.</li><li>Web based issue trackers are everywhere, with the ubiquitous "issue URL" allowing effective cross-linking between tracker issues, documentation, code comments, source control browsers, code review systems, etc.</li><li>Dedicated code review tools like <a href="https://code.google.com/p/gerrit/">Gerrit</a> and <a href="https://code.google.com/p/rietveld/">Reitveld</a> are published as open source (and, in the case of the latter, even available as a free service on <a href="http://codereview.appspot.com/">Google App Engine</a>).</li><li>Services like <a href="http://readthedocs.org/">ReadTheDocs</a> exist, allowing you to easily build and publish high quality documentation. All with nice URLs so you can link it from emails, tracker issues, source code, etc.</li><li>Organisations like <a href="https://www.shiningpanda.com/">Shining Panda CI</a> and <a href="http://travis-ci.org/">Travis CI</a> provide hosted continuous integration services that put the internal capabilities of many large companies to shame.</li><li>Language communities provide cross-platform distribution services to reach a global audience.</li><li>Depending on the language you use, you may even have tools like <a href="http://www.sonarsource.org/">SonarSource</a> available</li><li>Once you go into production in the web application world, service components like <a href="https://www.getsentry.com/welcome/">Sentry</a>, <a href="http://piwik.org/">Piwik</a>, and <a href="http://graphite.wikidot.com/faq">Graphite</a> are again available for no charge.</li></ol>And to access all this good stuff for free? All you have to do is be willing to share your work (and sometimes not even that). If you don't want to share your work, then the service providers generally have very reasonable fees - you could probably put together a state of the art suite of tools for less than a few hundred bucks a month.<br /><br />Take my own hobby projects as an example:<br /><ul><li>they're hosted on <a href="https://bitbucket.org/ncoghlan/">BitBucket</a> as Mercurial projects (I happen to prefer Mercurial, although I can definitely see why people like Git, too). That gives me integrated issue tracking and online source code browsing, too. (OK, so I could have had essentially that back in the early SourceForge days, but the UI aspects have improved in many respects in the intervening years)</li><li>I can publish my projects on the <a href="http://pypi.python.org/">Python Package Index</a> with a simple "<span>setup.py sdist upload</span>". They're then available for anyone in the world to install with a straightforward command like "<span>pip install walkdir</span>"</li><li>thanks to <a href="https://jenkins.shiningpanda.com/ncoghlan-devs-projects/">Shining Panda CI</a>, I know the downloads from PyPI work, and I also know that the projects work on all the versions and implementations of Python I want to support</li><li>thanks to <a href="http://readthedocs.org/profiles/ncoghlan/">ReadTheDocs</a> and <a href="http://sphinx.pocoo.org/">Sphinx</a>, you can read nicely formatted documentation like <a href="http://walkdir.readthedocs.org/">this</a> rather than trying to decipher plain text files or wiki pages.</li></ul>I'm living in the future and it is seriously <i>cool</i> (and that's just looking at things purely from a software development infrastructure point of view - the rise of "Infrastructure as a Service" and "Platform as a Service" providers, including Red Hat's own <a href="https://openshift.redhat.com/">OpenShift</a>, has massive implications on the deployment side of things, and there's of course the implications of the many open source wheels that don't need to be reinvented)<br /><br />The best part from my point of view is that these days I get to work for a <a href="http://www.redhat.com/">company</a> that already genuinely understands the long term significance of the power of collaborative development. It also doesn't hurt that there's still a lot of money to be made in helping the rest of the enterprise world come to grips with that reality :)<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/9320223-9142212041564052598?l=www.boredomandlaziness.org" alt="" /></div>]]></description>
    <link><![CDATA[http://www.boredomandlaziness.org/2012/05/embarrassment-of-riches.html]]></link>
    <pubDate>2012-05-22 17:40:34</pubDate>
  </item>
  <item>
    <title><![CDATA[Bryce Verdier: Project Euler: Problem 13]]></title>
    <description><![CDATA[<p>Problem thirteen from Project Euler is one of those problems that's so simple, I don't understand why it's in the double digits section. The problem reads: “Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.”<br />
It then proceeds to list 100 long numbers. I'm not going to paste them here because they are in the code solutions below and I don't want to clog up the <a href="http://lolcats.icanhascheezburger.com/2011/04/05/funny-pictures-the-internet-is-a-series-of-tubes/">“tubez”</a> with more redundant information than I'm about to.</p>
<p>Enough of my jibber-jabber.  Here is my Haskell solution first (trying to change things up here):<br />
<div class="geshifilter"><pre class="haskell geshifilter-haskell"><ol><li><div><span>module</span> Main <span>where</span></div></li><li><div>&nbsp;</div></li><li><div>main <span>::</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:IO"><span>IO</span></a><span>&#40;</span><span>&#41;</span></div></li><li><div>main <span>=</span> <span>do</span></div></li><li><div>    <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:print"><span>print</span></a> <span>.</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:take"><span>take</span></a> <span>10</span> <span>.</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:show"><span>show</span></a> <span>$</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:sum"><span>sum</span></a> big<span>_</span>number</div></li><li><div>    <span>where</span> big<span>_</span>number <span>=</span> <span>&#91;</span> <span>37107287533902102798797998220837590246510135740250</span></div></li><li><div>                       <span>,</span> <span>46376937677490009712648124896970078050417018260538</span></div></li><li><div>                       <span>,</span> <span>74324986199524741059474233309513058123726617309629</span></div></li><li><div>                       <span>,</span> <span>91942213363574161572522430563301811072406154908250</span></div></li><li><div>                       <span>,</span> <span>23067588207539346171171980310421047513778063246676</span></div></li><li><div>                       <span>,</span> <span>89261670696623633820136378418383684178734361726757</span></div></li><li><div>                       <span>,</span> <span>28112879812849979408065481931592621691275889832738</span></div></li><li><div>                       <span>,</span> <span>44274228917432520321923589422876796487670272189318</span></div></li><li><div>                       <span>,</span> <span>47451445736001306439091167216856844588711603153276</span></div></li><li><div>                       <span>,</span> <span>70386486105843025439939619828917593665686757934951</span></div></li><li><div>                       <span>,</span> <span>62176457141856560629502157223196586755079324193331</span></div></li><li><div>                       <span>,</span> <span>64906352462741904929101432445813822663347944758178</span></div></li><li><div>                       <span>,</span> <span>92575867718337217661963751590579239728245598838407</span></div></li><li><div>                       <span>,</span> <span>58203565325359399008402633568948830189458628227828</span></div></li><li><div>                       <span>,</span> <span>80181199384826282014278194139940567587151170094390</span></div></li><li><div>                       <span>,</span> <span>35398664372827112653829987240784473053190104293586</span></div></li><li><div>                       <span>,</span> <span>86515506006295864861532075273371959191420517255829</span></div></li><li><div>                       <span>,</span> <span>71693888707715466499115593487603532921714970056938</span></div></li><li><div>                       <span>,</span> <span>54370070576826684624621495650076471787294438377604</span></div></li><li><div>                       <span>,</span> <span>53282654108756828443191190634694037855217779295145</span></div></li><li><div>                       <span>,</span> <span>36123272525000296071075082563815656710885258350721</span></div></li><li><div>                       <span>,</span> <span>45876576172410976447339110607218265236877223636045</span></div></li><li><div>                       <span>,</span> <span>17423706905851860660448207621209813287860733969412</span></div></li><li><div>                       <span>,</span> <span>81142660418086830619328460811191061556940512689692</span></div></li><li><div>                       <span>,</span> <span>51934325451728388641918047049293215058642563049483</span></div></li><li><div>                       <span>,</span> <span>62467221648435076201727918039944693004732956340691</span></div></li><li><div>                       <span>,</span> <span>15732444386908125794514089057706229429197107928209</span></div></li><li><div>                       <span>,</span> <span>55037687525678773091862540744969844508330393682126</span></div></li><li><div>                       <span>,</span> <span>18336384825330154686196124348767681297534375946515</span></div></li><li><div>                       <span>,</span> <span>80386287592878490201521685554828717201219257766954</span></div></li><li><div>                       <span>,</span> <span>78182833757993103614740356856449095527097864797581</span></div></li><li><div>                       <span>,</span> <span>16726320100436897842553539920931837441497806860984</span></div></li><li><div>                       <span>,</span> <span>48403098129077791799088218795327364475675590848030</span></div></li><li><div>                       <span>,</span> <span>87086987551392711854517078544161852424320693150332</span></div></li><li><div>                       <span>,</span> <span>59959406895756536782107074926966537676326235447210</span></div></li><li><div>                       <span>,</span> <span>69793950679652694742597709739166693763042633987085</span></div></li><li><div>                       <span>,</span> <span>41052684708299085211399427365734116182760315001271</span></div></li><li><div>                       <span>,</span> <span>65378607361501080857009149939512557028198746004375</span></div></li><li><div>                       <span>,</span> <span>35829035317434717326932123578154982629742552737307</span></div></li><li><div>                       <span>,</span> <span>94953759765105305946966067683156574377167401875275</span></div></li><li><div>                       <span>,</span> <span>88902802571733229619176668713819931811048770190271</span></div></li><li><div>                       <span>,</span> <span>25267680276078003013678680992525463401061632866526</span></div></li><li><div>                       <span>,</span> <span>36270218540497705585629946580636237993140746255962</span></div></li><li><div>                       <span>,</span> <span>24074486908231174977792365466257246923322810917141</span></div></li><li><div>                       <span>,</span> <span>91430288197103288597806669760892938638285025333403</span></div></li><li><div>                       <span>,</span> <span>34413065578016127815921815005561868836468420090470</span></div></li><li><div>                       <span>,</span> <span>23053081172816430487623791969842487255036638784583</span></div></li><li><div>                       <span>,</span> <span>11487696932154902810424020138335124462181441773470</span></div></li><li><div>                       <span>,</span> <span>63783299490636259666498587618221225225512486764533</span></div></li><li><div>                       <span>,</span> <span>67720186971698544312419572409913959008952310058822</span></div></li><li><div>                       <span>,</span> <span>95548255300263520781532296796249481641953868218774</span></div></li><li><div>                       <span>,</span> <span>76085327132285723110424803456124867697064507995236</span></div></li><li><div>                       <span>,</span> <span>37774242535411291684276865538926205024910326572967</span></div></li><li><div>                       <span>,</span> <span>23701913275725675285653248258265463092207058596522</span></div></li><li><div>                       <span>,</span> <span>29798860272258331913126375147341994889534765745501</span></div></li><li><div>                       <span>,</span> <span>18495701454879288984856827726077713721403798879715</span></div></li><li><div>                       <span>,</span> <span>38298203783031473527721580348144513491373226651381</span></div></li><li><div>                       <span>,</span> <span>34829543829199918180278916522431027392251122869539</span></div></li><li><div>                       <span>,</span> <span>40957953066405232632538044100059654939159879593635</span></div></li><li><div>                       <span>,</span> <span>29746152185502371307642255121183693803580388584903</span></div></li><li><div>                       <span>,</span> <span>41698116222072977186158236678424689157993532961922</span></div></li><li><div>                       <span>,</span> <span>62467957194401269043877107275048102390895523597457</span></div></li><li><div>                       <span>,</span> <span>23189706772547915061505504953922979530901129967519</span></div></li><li><div>                       <span>,</span> <span>86188088225875314529584099251203829009407770775672</span></div></li><li><div>                       <span>,</span> <span>11306739708304724483816533873502340845647058077308</span></div></li><li><div>                       <span>,</span> <span>82959174767140363198008187129011875491310547126581</span></div></li><li><div>                       <span>,</span> <span>97623331044818386269515456334926366572897563400500</span></div></li><li><div>                       <span>,</span> <span>42846280183517070527831839425882145521227251250327</span></div></li><li><div>                       <span>,</span> <span>55121603546981200581762165212827652751691296897789</span></div></li><li><div>                       <span>,</span> <span>32238195734329339946437501907836945765883352399886</span></div></li><li><div>                       <span>,</span> <span>75506164965184775180738168837861091527357929701337</span></div></li><li><div>                       <span>,</span> <span>62177842752192623401942399639168044983993173312731</span></div></li><li><div>                       <span>,</span> <span>32924185707147349566916674687634660915035914677504</span></div></li><li><div>                       <span>,</span> <span>99518671430235219628894890102423325116913619626622</span></div></li><li><div>                       <span>,</span> <span>73267460800591547471830798392868535206946944540724</span></div></li><li><div>                       <span>,</span> <span>76841822524674417161514036427982273348055556214818</span></div></li><li><div>                       <span>,</span> <span>97142617910342598647204516893989422179826088076852</span></div></li><li><div>                       <span>,</span> <span>87783646182799346313767754307809363333018982642090</span></div></li><li><div>                       <span>,</span> <span>10848802521674670883215120185883543223812876952786</span></div></li><li><div>                       <span>,</span> <span>71329612474782464538636993009049310363619763878039</span></div></li><li><div>                       <span>,</span> <span>62184073572399794223406235393808339651327408011116</span></div></li><li><div>                       <span>,</span> <span>66627891981488087797941876876144230030984490851411</span></div></li><li><div>                       <span>,</span> <span>60661826293682836764744779239180335110989069790714</span></div></li><li><div>                       <span>,</span> <span>85786944089552990653640447425576083659976645795096</span></div></li><li><div>                       <span>,</span> <span>66024396409905389607120198219976047599490197230297</span></div></li><li><div>                       <span>,</span> <span>64913982680032973156037120041377903785566085089252</span></div></li><li><div>                       <span>,</span> <span>16730939319872750275468906903707539413042652315011</span></div></li><li><div>                       <span>,</span> <span>94809377245048795150954100921645863754710598436791</span></div></li><li><div>                       <span>,</span> <span>78639167021187492431995700641917969777599028300699</span></div></li><li><div>                       <span>,</span> <span>15368713711936614952811305876380278410754449733078</span></div></li><li><div>                       <span>,</span> <span>40789923115535562561142322423255033685442488917353</span></div></li><li><div>                       <span>,</span> <span>44889911501440648020369068063960672322193204149535</span></div></li><li><div>                       <span>,</span> <span>41503128880339536053299340368006977710650566631954</span></div></li><li><div>                       <span>,</span> <span>81234880673210146739058568557934581403627822703280</span></div></li><li><div>                       <span>,</span> <span>82616570773948327592232845941706525094512325230608</span></div></li><li><div>                       <span>,</span> <span>22918802058777319719839450180888072429661980811197</span></div></li><li><div>                       <span>,</span> <span>77158542502016545090413245809786882778948721859617</span></div></li><li><div>                       <span>,</span> <span>72107838435069186155435662884062257473692284509516</span></div></li><li><div>                       <span>,</span> <span>20849603980134001723930671666823555245252804609722</span></div></li><li><div>                       <span>,</span> <span>53503534226472524250874054075591789781264330331690</span><span>&#93;</span></div></li></ol></pre></div></p>
<p>followed by my Python solution:<br />
<div class="geshifilter"><pre class="python geshifilter-python"><ol><li><div><span>#!/usr/bin/python</span></div></li><li><div><span>&quot;&quot;&quot;</span></div></li><li><div><span>code solution for project euler's problem #13 in python.</span></div></li><li><div><span>&quot;&quot;&quot;</span></div></li><li><div><span>from</span> <span>__future__</span> <span>import</span> print_function</div></li><li><div>&nbsp;</div></li><li><div><span>def</span> print_10<span>&#40;</span>number<span>&#41;</span>:</div></li><li><div>    <span>print</span><span>&#40;</span><span>str</span><span>&#40;</span>number<span>&#41;</span><span>&#91;</span><span>0</span>:<span>10</span><span>&#93;</span><span>&#41;</span></div></li><li><div>&nbsp;</div></li><li><div><span>if</span> __name__ <span>==</span> <span>&quot;__main__&quot;</span>:</div></li><li><div>&nbsp;</div></li><li><div>    big_number <span>=</span> <span>&#91;</span> <span>37107287533902102798797998220837590246510135740250</span><span>,</span></div></li><li><div>                   <span>46376937677490009712648124896970078050417018260538</span><span>,</span></div></li><li><div>                   <span>74324986199524741059474233309513058123726617309629</span><span>,</span></div></li><li><div>                   <span>91942213363574161572522430563301811072406154908250</span><span>,</span></div></li><li><div>                   <span>23067588207539346171171980310421047513778063246676</span><span>,</span></div></li><li><div>                   <span>89261670696623633820136378418383684178734361726757</span><span>,</span></div></li><li><div>                   <span>28112879812849979408065481931592621691275889832738</span><span>,</span></div></li><li><div>                   <span>44274228917432520321923589422876796487670272189318</span><span>,</span></div></li><li><div>                   <span>47451445736001306439091167216856844588711603153276</span><span>,</span></div></li><li><div>                   <span>70386486105843025439939619828917593665686757934951</span><span>,</span></div></li><li><div>                   <span>62176457141856560629502157223196586755079324193331</span><span>,</span></div></li><li><div>                   <span>64906352462741904929101432445813822663347944758178</span><span>,</span></div></li><li><div>                   <span>92575867718337217661963751590579239728245598838407</span><span>,</span></div></li><li><div>                   <span>58203565325359399008402633568948830189458628227828</span><span>,</span></div></li><li><div>                   <span>80181199384826282014278194139940567587151170094390</span><span>,</span></div></li><li><div>                   <span>35398664372827112653829987240784473053190104293586</span><span>,</span></div></li><li><div>                   <span>86515506006295864861532075273371959191420517255829</span><span>,</span></div></li><li><div>                   <span>71693888707715466499115593487603532921714970056938</span><span>,</span></div></li><li><div>                   <span>54370070576826684624621495650076471787294438377604</span><span>,</span></div></li><li><div>                   <span>53282654108756828443191190634694037855217779295145</span><span>,</span></div></li><li><div>                   <span>36123272525000296071075082563815656710885258350721</span><span>,</span></div></li><li><div>                   <span>45876576172410976447339110607218265236877223636045</span><span>,</span></div></li><li><div>                   <span>17423706905851860660448207621209813287860733969412</span><span>,</span></div></li><li><div>                   <span>81142660418086830619328460811191061556940512689692</span><span>,</span></div></li><li><div>                   <span>51934325451728388641918047049293215058642563049483</span><span>,</span></div></li><li><div>                   <span>62467221648435076201727918039944693004732956340691</span><span>,</span></div></li><li><div>                   <span>15732444386908125794514089057706229429197107928209</span><span>,</span></div></li><li><div>                   <span>55037687525678773091862540744969844508330393682126</span><span>,</span></div></li><li><div>                   <span>18336384825330154686196124348767681297534375946515</span><span>,</span></div></li><li><div>                   <span>80386287592878490201521685554828717201219257766954</span><span>,</span></div></li><li><div>                   <span>78182833757993103614740356856449095527097864797581</span><span>,</span></div></li><li><div>                   <span>16726320100436897842553539920931837441497806860984</span><span>,</span></div></li><li><div>                   <span>48403098129077791799088218795327364475675590848030</span><span>,</span></div></li><li><div>                   <span>87086987551392711854517078544161852424320693150332</span><span>,</span></div></li><li><div>                   <span>59959406895756536782107074926966537676326235447210</span><span>,</span></div></li><li><div>                   <span>69793950679652694742597709739166693763042633987085</span><span>,</span></div></li><li><div>                   <span>41052684708299085211399427365734116182760315001271</span><span>,</span></div></li><li><div>                   <span>65378607361501080857009149939512557028198746004375</span><span>,</span></div></li><li><div>                   <span>35829035317434717326932123578154982629742552737307</span><span>,</span></div></li><li><div>                   <span>94953759765105305946966067683156574377167401875275</span><span>,</span></div></li><li><div>                   <span>88902802571733229619176668713819931811048770190271</span><span>,</span></div></li><li><div>                   <span>25267680276078003013678680992525463401061632866526</span><span>,</span></div></li><li><div>                   <span>36270218540497705585629946580636237993140746255962</span><span>,</span></div></li><li><div>                   <span>24074486908231174977792365466257246923322810917141</span><span>,</span></div></li><li><div>                   <span>91430288197103288597806669760892938638285025333403</span><span>,</span></div></li><li><div>                   <span>34413065578016127815921815005561868836468420090470</span><span>,</span></div></li><li><div>                   <span>23053081172816430487623791969842487255036638784583</span><span>,</span></div></li><li><div>                   <span>11487696932154902810424020138335124462181441773470</span><span>,</span></div></li><li><div>                   <span>63783299490636259666498587618221225225512486764533</span><span>,</span></div></li><li><div>                   <span>67720186971698544312419572409913959008952310058822</span><span>,</span></div></li><li><div>                   <span>95548255300263520781532296796249481641953868218774</span><span>,</span></div></li><li><div>                   <span>76085327132285723110424803456124867697064507995236</span><span>,</span></div></li><li><div>                   <span>37774242535411291684276865538926205024910326572967</span><span>,</span></div></li><li><div>                   <span>23701913275725675285653248258265463092207058596522</span><span>,</span></div></li><li><div>                   <span>29798860272258331913126375147341994889534765745501</span><span>,</span></div></li><li><div>                   <span>18495701454879288984856827726077713721403798879715</span><span>,</span></div></li><li><div>                   <span>38298203783031473527721580348144513491373226651381</span><span>,</span></div></li><li><div>                   <span>34829543829199918180278916522431027392251122869539</span><span>,</span></div></li><li><div>                   <span>40957953066405232632538044100059654939159879593635</span><span>,</span></div></li><li><div>                   <span>29746152185502371307642255121183693803580388584903</span><span>,</span></div></li><li><div>                   <span>41698116222072977186158236678424689157993532961922</span><span>,</span></div></li><li><div>                   <span>62467957194401269043877107275048102390895523597457</span><span>,</span></div></li><li><div>                   <span>23189706772547915061505504953922979530901129967519</span><span>,</span></div></li><li><div>                   <span>86188088225875314529584099251203829009407770775672</span><span>,</span></div></li><li><div>                   <span>11306739708304724483816533873502340845647058077308</span><span>,</span></div></li><li><div>                   <span>82959174767140363198008187129011875491310547126581</span><span>,</span></div></li><li><div>                   <span>97623331044818386269515456334926366572897563400500</span><span>,</span></div></li><li><div>                   <span>42846280183517070527831839425882145521227251250327</span><span>,</span></div></li><li><div>                   <span>55121603546981200581762165212827652751691296897789</span><span>,</span></div></li><li><div>                   <span>32238195734329339946437501907836945765883352399886</span><span>,</span></div></li><li><div>                   <span>75506164965184775180738168837861091527357929701337</span><span>,</span></div></li><li><div>                   <span>62177842752192623401942399639168044983993173312731</span><span>,</span></div></li><li><div>                   <span>32924185707147349566916674687634660915035914677504</span><span>,</span></div></li><li><div>                   <span>99518671430235219628894890102423325116913619626622</span><span>,</span></div></li><li><div>                   <span>73267460800591547471830798392868535206946944540724</span><span>,</span></div></li><li><div>                   <span>76841822524674417161514036427982273348055556214818</span><span>,</span></div></li><li><div>                   <span>97142617910342598647204516893989422179826088076852</span><span>,</span></div></li><li><div>                   <span>87783646182799346313767754307809363333018982642090</span><span>,</span></div></li><li><div>                   <span>10848802521674670883215120185883543223812876952786</span><span>,</span></div></li><li><div>                   <span>71329612474782464538636993009049310363619763878039</span><span>,</span></div></li><li><div>                   <span>62184073572399794223406235393808339651327408011116</span><span>,</span></div></li><li><div>                   <span>66627891981488087797941876876144230030984490851411</span><span>,</span></div></li><li><div>                   <span>60661826293682836764744779239180335110989069790714</span><span>,</span></div></li><li><div>                   <span>85786944089552990653640447425576083659976645795096</span><span>,</span></div></li><li><div>                   <span>66024396409905389607120198219976047599490197230297</span><span>,</span></div></li><li><div>                   <span>64913982680032973156037120041377903785566085089252</span><span>,</span></div></li><li><div>                   <span>16730939319872750275468906903707539413042652315011</span><span>,</span></div></li><li><div>                   <span>94809377245048795150954100921645863754710598436791</span><span>,</span></div></li><li><div>                   <span>78639167021187492431995700641917969777599028300699</span><span>,</span></div></li><li><div>                   <span>15368713711936614952811305876380278410754449733078</span><span>,</span></div></li><li><div>                   <span>40789923115535562561142322423255033685442488917353</span><span>,</span></div></li><li><div>                   <span>44889911501440648020369068063960672322193204149535</span><span>,</span></div></li><li><div>                   <span>41503128880339536053299340368006977710650566631954</span><span>,</span></div></li><li><div>                   <span>81234880673210146739058568557934581403627822703280</span><span>,</span></div></li><li><div>                   <span>82616570773948327592232845941706525094512325230608</span><span>,</span></div></li><li><div>                   <span>22918802058777319719839450180888072429661980811197</span><span>,</span></div></li><li><div>                   <span>77158542502016545090413245809786882778948721859617</span><span>,</span></div></li><li><div>                   <span>72107838435069186155435662884062257473692284509516</span><span>,</span></div></li><li><div>                   <span>20849603980134001723930671666823555245252804609722</span><span>,</span></div></li><li><div>                   <span>53503534226472524250874054075591789781264330331690</span><span>&#93;</span></div></li><li><div>&nbsp;</div></li><li><div>    print_10<span>&#40;</span><span>sum</span><span>&#40;</span>big_number<span>&#41;</span><span>&#41;</span></div></li></ol></pre></div></p>
<p>and to continue adding in the spice, I have included a solution in Scala:<br />
<div class="geshifilter"><pre class="scala geshifilter-scala"><ol><li><div><a href="http://scala-lang.org"><span>import</span></a> BigInt.<span>_</span></div></li><li><div>&nbsp;</div></li><li><div><a href="http://scala-lang.org"><span>object</span></a> problem<span>_</span>13 <span>&#123;</span></div></li><li><div>    <a href="http://scala-lang.org"><span>def</span></a> main <span>&#40;</span>args <span>:</span> Array<span>&#91;</span>String<span>&#93;</span><span>&#41;</span><span>&#123;</span></div></li><li><div>        <a href="http://scala-lang.org"><span>val</span></a> big<span>_</span>number <span>=</span> List<span>&#40;</span><span>&quot;37107287533902102798797998220837590246510135740250&quot;</span>,</div></li><li><div>                              <span>&quot;46376937677490009712648124896970078050417018260538&quot;</span>,</div></li><li><div>                              <span>&quot;74324986199524741059474233309513058123726617309629&quot;</span>,</div></li><li><div>                              <span>&quot;91942213363574161572522430563301811072406154908250&quot;</span>,</div></li><li><div>                              <span>&quot;23067588207539346171171980310421047513778063246676&quot;</span>,</div></li><li><div>                              <span>&quot;89261670696623633820136378418383684178734361726757&quot;</span>,</div></li><li><div>                              <span>&quot;28112879812849979408065481931592621691275889832738&quot;</span>,</div></li><li><div>                              <span>&quot;44274228917432520321923589422876796487670272189318&quot;</span>,</div></li><li><div>                              <span>&quot;47451445736001306439091167216856844588711603153276&quot;</span>,</div></li><li><div>                              <span>&quot;70386486105843025439939619828917593665686757934951&quot;</span>,</div></li><li><div>                              <span>&quot;62176457141856560629502157223196586755079324193331&quot;</span>,</div></li><li><div>                              <span>&quot;64906352462741904929101432445813822663347944758178&quot;</span>,</div></li><li><div>                              <span>&quot;92575867718337217661963751590579239728245598838407&quot;</span>,</div></li><li><div>                              <span>&quot;58203565325359399008402633568948830189458628227828&quot;</span>,</div></li><li><div>                              <span>&quot;80181199384826282014278194139940567587151170094390&quot;</span>,</div></li><li><div>                              <span>&quot;35398664372827112653829987240784473053190104293586&quot;</span>,</div></li><li><div>                              <span>&quot;86515506006295864861532075273371959191420517255829&quot;</span>,</div></li><li><div>                              <span>&quot;71693888707715466499115593487603532921714970056938&quot;</span>,</div></li><li><div>                              <span>&quot;54370070576826684624621495650076471787294438377604&quot;</span>,</div></li><li><div>                              <span>&quot;53282654108756828443191190634694037855217779295145&quot;</span>,</div></li><li><div>                              <span>&quot;36123272525000296071075082563815656710885258350721&quot;</span>,</div></li><li><div>                              <span>&quot;45876576172410976447339110607218265236877223636045&quot;</span>,</div></li><li><div>                              <span>&quot;17423706905851860660448207621209813287860733969412&quot;</span>,</div></li><li><div>                              <span>&quot;81142660418086830619328460811191061556940512689692&quot;</span>,</div></li><li><div>                              <span>&quot;51934325451728388641918047049293215058642563049483&quot;</span>,</div></li><li><div>                              <span>&quot;62467221648435076201727918039944693004732956340691&quot;</span>,</div></li><li><div>                              <span>&quot;15732444386908125794514089057706229429197107928209&quot;</span>,</div></li><li><div>                              <span>&quot;55037687525678773091862540744969844508330393682126&quot;</span>,</div></li><li><div>                              <span>&quot;18336384825330154686196124348767681297534375946515&quot;</span>,</div></li><li><div>                              <span>&quot;80386287592878490201521685554828717201219257766954&quot;</span>,</div></li><li><div>                              <span>&quot;78182833757993103614740356856449095527097864797581&quot;</span>,</div></li><li><div>                              <span>&quot;16726320100436897842553539920931837441497806860984&quot;</span>,</div></li><li><div>                              <span>&quot;48403098129077791799088218795327364475675590848030&quot;</span>,</div></li><li><div>                              <span>&quot;87086987551392711854517078544161852424320693150332&quot;</span>,</div></li><li><div>                              <span>&quot;59959406895756536782107074926966537676326235447210&quot;</span>,</div></li><li><div>                              <span>&quot;69793950679652694742597709739166693763042633987085&quot;</span>,</div></li><li><div>                              <span>&quot;41052684708299085211399427365734116182760315001271&quot;</span>,</div></li><li><div>                              <span>&quot;65378607361501080857009149939512557028198746004375&quot;</span>,</div></li><li><div>                              <span>&quot;35829035317434717326932123578154982629742552737307&quot;</span>,</div></li><li><div>                              <span>&quot;94953759765105305946966067683156574377167401875275&quot;</span>,</div></li><li><div>                              <span>&quot;88902802571733229619176668713819931811048770190271&quot;</span>,</div></li><li><div>                              <span>&quot;25267680276078003013678680992525463401061632866526&quot;</span>,</div></li><li><div>                              <span>&quot;36270218540497705585629946580636237993140746255962&quot;</span>,</div></li><li><div>                              <span>&quot;24074486908231174977792365466257246923322810917141&quot;</span>,</div></li><li><div>                              <span>&quot;91430288197103288597806669760892938638285025333403&quot;</span>,</div></li><li><div>                              <span>&quot;34413065578016127815921815005561868836468420090470&quot;</span>,</div></li><li><div>                              <span>&quot;23053081172816430487623791969842487255036638784583&quot;</span>,</div></li><li><div>                              <span>&quot;11487696932154902810424020138335124462181441773470&quot;</span>,</div></li><li><div>                              <span>&quot;63783299490636259666498587618221225225512486764533&quot;</span>,</div></li><li><div>                              <span>&quot;67720186971698544312419572409913959008952310058822&quot;</span>,</div></li><li><div>                              <span>&quot;95548255300263520781532296796249481641953868218774&quot;</span>,</div></li><li><div>                              <span>&quot;76085327132285723110424803456124867697064507995236&quot;</span>,</div></li><li><div>                              <span>&quot;37774242535411291684276865538926205024910326572967&quot;</span>,</div></li><li><div>                              <span>&quot;23701913275725675285653248258265463092207058596522&quot;</span>,</div></li><li><div>                              <span>&quot;29798860272258331913126375147341994889534765745501&quot;</span>,</div></li><li><div>                              <span>&quot;18495701454879288984856827726077713721403798879715&quot;</span>,</div></li><li><div>                              <span>&quot;38298203783031473527721580348144513491373226651381&quot;</span>,</div></li><li><div>                              <span>&quot;34829543829199918180278916522431027392251122869539&quot;</span>,</div></li><li><div>                              <span>&quot;40957953066405232632538044100059654939159879593635&quot;</span>,</div></li><li><div>                              <span>&quot;29746152185502371307642255121183693803580388584903&quot;</span>,</div></li><li><div>                              <span>&quot;41698116222072977186158236678424689157993532961922&quot;</span>,</div></li><li><div>                              <span>&quot;62467957194401269043877107275048102390895523597457&quot;</span>,</div></li><li><div>                              <span>&quot;23189706772547915061505504953922979530901129967519&quot;</span>,</div></li><li><div>                              <span>&quot;86188088225875314529584099251203829009407770775672&quot;</span>,</div></li><li><div>                              <span>&quot;11306739708304724483816533873502340845647058077308&quot;</span>,</div></li><li><div>                              <span>&quot;82959174767140363198008187129011875491310547126581&quot;</span>,</div></li><li><div>                              <span>&quot;97623331044818386269515456334926366572897563400500&quot;</span>,</div></li><li><div>                              <span>&quot;42846280183517070527831839425882145521227251250327&quot;</span>,</div></li><li><div>                              <span>&quot;55121603546981200581762165212827652751691296897789&quot;</span>,</div></li><li><div>                              <span>&quot;32238195734329339946437501907836945765883352399886&quot;</span>,</div></li><li><div>                              <span>&quot;75506164965184775180738168837861091527357929701337&quot;</span>,</div></li><li><div>                              <span>&quot;62177842752192623401942399639168044983993173312731&quot;</span>,</div></li><li><div>                              <span>&quot;32924185707147349566916674687634660915035914677504&quot;</span>,</div></li><li><div>                              <span>&quot;99518671430235219628894890102423325116913619626622&quot;</span>,</div></li><li><div>                              <span>&quot;73267460800591547471830798392868535206946944540724&quot;</span>,</div></li><li><div>                              <span>&quot;76841822524674417161514036427982273348055556214818&quot;</span>,</div></li><li><div>                              <span>&quot;97142617910342598647204516893989422179826088076852&quot;</span>,</div></li><li><div>                              <span>&quot;87783646182799346313767754307809363333018982642090&quot;</span>,</div></li><li><div>                              <span>&quot;10848802521674670883215120185883543223812876952786&quot;</span>,</div></li><li><div>                              <span>&quot;71329612474782464538636993009049310363619763878039&quot;</span>,</div></li><li><div>                              <span>&quot;62184073572399794223406235393808339651327408011116&quot;</span>,</div></li><li><div>                              <span>&quot;66627891981488087797941876876144230030984490851411&quot;</span>,</div></li><li><div>                              <span>&quot;60661826293682836764744779239180335110989069790714&quot;</span>,</div></li><li><div>                              <span>&quot;85786944089552990653640447425576083659976645795096&quot;</span>,</div></li><li><div>                              <span>&quot;66024396409905389607120198219976047599490197230297&quot;</span>,</div></li><li><div>                              <span>&quot;64913982680032973156037120041377903785566085089252&quot;</span>,</div></li><li><div>                              <span>&quot;16730939319872750275468906903707539413042652315011&quot;</span>,</div></li><li><div>                              <span>&quot;94809377245048795150954100921645863754710598436791&quot;</span>,</div></li><li><div>                              <span>&quot;78639167021187492431995700641917969777599028300699&quot;</span>,</div></li><li><div>                              <span>&quot;15368713711936614952811305876380278410754449733078&quot;</span>,</div></li><li><div>                              <span>&quot;40789923115535562561142322423255033685442488917353&quot;</span>,</div></li><li><div>                              <span>&quot;44889911501440648020369068063960672322193204149535&quot;</span>,</div></li><li><div>                              <span>&quot;41503128880339536053299340368006977710650566631954&quot;</span>,</div></li><li><div>                              <span>&quot;81234880673210146739058568557934581403627822703280&quot;</span>,</div></li><li><div>                              <span>&quot;82616570773948327592232845941706525094512325230608&quot;</span>,</div></li><li><div>                              <span>&quot;22918802058777319719839450180888072429661980811197&quot;</span>,</div></li><li><div>                              <span>&quot;77158542502016545090413245809786882778948721859617&quot;</span>,</div></li><li><div>                              <span>&quot;72107838435069186155435662884062257473692284509516&quot;</span>,</div></li><li><div>                              <span>&quot;20849603980134001723930671666823555245252804609722&quot;</span>,</div></li><li><div>                              <span>&quot;53503534226472524250874054075591789781264330331690&quot;</span><span>&#41;</span> map <span>&#123;</span>BigInt<span>&#40;</span><span>_</span><span>&#41;</span><span>&#125;</span></div></li><li><div>        <a href="http://scala-lang.org"><span>val</span></a> sums <span>=</span> big<span>_</span>number sum</div></li><li><div>        <a href="http://scala-lang.org"><span>val</span></a> su <span>=</span> sums toString</div></li><li><div>        <a href="http://scala-lang.org"><span>val</span></a> su10 <span>=</span> su take <span>10</span></div></li><li><div>        println<span>&#40;</span>su10<span>&#41;</span></div></li><li><div>    <span>&#125;</span></div></li><li><div><span>&#125;</span></div></li></ol></pre></div><br />
Some of you may be wondering, “Why a Scala solution?”  To which I respond, “Why not?”  Because that's a little short, I'll add that it has something to do with Scala starting to gain traction in the industry and me seeing if I would like to get paid to program in it.</p>
<p>The solution, in all three languages, is pretty simple. The recipe essentially says, “Put all numbers into a list.  Get the sum of that list, turn that number into a string, and get the first 10 characters of that string.”</p>
<p>Times:<br />
Haskell (compiled)   : real	0m0.004s<br />
Haskell (runghc)     : real	0m0.314s<br />
Python               : real	0m0.059s<br />
Scala   (compiled)   : real	0m0.757s</p>
<p>For the most part it's pretty standard in these tests to see performance times such that Haskell (compiled)  Python  Haskell (runghc). Java and Perl usually fall somewhere between the Haskell (compiled) and Python, in that order. To see Scala be 2x slower than Haskell (runghc) was a shocker.  The only thing that makes sense to me for the slowdown is having to use the BigInt library. That is probably the biggest thing I took away from these time tests - if I want to do REALLY large number crunching and performance DOES matter, JVM-based languages might not be the best option. </p>
<p>A few thoughts on Scala:<br />
If I haven't stated it already in this blog, I should now give the disclaimer that I'm not a Java fan.  I know it still has its loyal followers, but I'm not one of them.  Moving on.  This was my first time working with Scala, and I'd like to finally welcome Java to the 21st century.  While doing some research on the Scala language itself I read that “the industry” was moving to replace Java with Scala.  I welcome that change.  Does that mean I “like” Scala?  The honest answer is, to butcher the quote the appliances from the Flintstones, “Eh, it's a language.” Scala is definitely an improvement over Java – not really that hard to do in my opinion – but, the language still feels unpolished.  One quick way to kill the interpreter in Scala is to type “Int” then hit the enter key.  Instead of error-ing out, the interpreter does a great job of interpreting a crash test car hitting a cement wall (I had to restart the whole thing.)  When I tried the same “technique” in the Python interpreter, I got  as a response and for Haskell's interpreter I received “Not in scope: data constructor `Int'”.  I also found Scala's function composition to be a little lacking when compared to Haskell.  I wasn't able to cleanly change the BigInt data type to String, and then only print out ten characters without requiring three separate val's.  Yes, I could have used one var instead, but that's beside the point. I will admit it could be my inexperience with the language showing, so if anyone knows a smoother way to do this in Scala please share it in the comments.</p>
<p>All that being said, I do like the way Scala is trying to handle the reducing of Java's dot notation, and I think it's starting to make strides in the right direction in other areas.  I'm open to working with Scala more, and look forward to seeing how it evolves over the next few years.  </p>]]></description>
    <link><![CDATA[http://scrollingtext.org/project-euler-problem-13]]></link>
    <pubDate>2012-05-22 16:48:04</pubDate>
  </item>
  <item>
    <title><![CDATA[Daniel Greenfeld: Simple Django email form using CBV]]></title>
    <description><![CDATA[<p>Here's a simple <tt class="docutils literal">FormView</tt> Class Based Views for <a class="reference external" href="http://djangoproject.com">Django</a>. Here is a sample of how to do one as a simple email form. There is no CAPTCHA in this example, that's the topic of a future blog post.</p>
<p>This version requires the following packages <tt class="docutils literal">pip</tt> installed into your <tt class="docutils literal">virtualenv</tt>.</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">django-crispy-forms</span></tt> so we can do Python driven layouts.</li>
<li><tt class="docutils literal"><span class="pre">django-floppyforms</span></tt> so we get HTML5 elements for free.</li>
</ul>
<p>They also need to be added to your list of INSTALLED_APPS:</p>
<div class="highlight"><pre><span class="n">INSTALLED_APPS</span> <span class="o">+=</span> <span class="p">(</span>
    <span class="s">'crispy_forms'</span><span class="p">,</span>
    <span class="s">'floppyforms'</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>In myapp.forms.py:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">crispy_forms.helper</span> <span class="kn">import</span> <span class="n">FormHelper</span>
<span class="kn">from</span> <span class="nn">crispy_forms.layout</span> <span class="kn">import</span> <span class="n">Submit</span>
<span class="kn">import</span> <span class="nn">floppyforms</span> <span class="kn">as</span> <span class="nn">forms</span>

<span class="k">class</span> <span class="nc">ContactForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>

    <span class="n">name</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">email</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">EmailField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">subject</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">message</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">Textarea</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">helper</span> <span class="o">=</span> <span class="n">FormHelper</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">helper</span><span class="o">.</span><span class="n">add_input</span><span class="p">(</span><span class="n">Submit</span><span class="p">(</span><span class="s">'submit'</span><span class="p">,</span> <span class="s">'Submit'</span><span class="p">))</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">ContactForm</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
<p>In myapp.views.py:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.core.mail</span> <span class="kn">import</span> <span class="n">send_mail</span>
<span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">FormView</span>

<span class="kn">from</span> <span class="nn">myapp.forms</span> <span class="kn">import</span> <span class="n">ContactForm</span>

<span class="k">class</span> <span class="nc">ContactFormView</span><span class="p">(</span><span class="n">FormView</span><span class="p">):</span>

    <span class="n">form_class</span> <span class="o">=</span> <span class="n">ContactForm</span>
    <span class="n">template_name</span> <span class="o">=</span> <span class="s">&quot;myapp/email_form.html&quot;</span>
    <span class="n">success_url</span> <span class="o">=</span> <span class="s">'/email-sent/'</span>

    <span class="k">def</span> <span class="nf">form_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">form</span><span class="p">):</span>
        <span class="n">message</span> <span class="o">=</span> <span class="s">&quot;{name} / {email} said: &quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
            <span class="n">name</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'name'</span><span class="p">),</span>
            <span class="n">email</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'email'</span><span class="p">))</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="s">&quot;</span><span class="se">\n\n</span><span class="s">{0}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'message'</span><span class="p">))</span>
        <span class="n">send_mail</span><span class="p">(</span>
            <span class="n">subject</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'subject'</span><span class="p">),</span>
            <span class="n">message</span><span class="o">=</span><span class="n">message</span><span class="p">,</span>
            <span class="n">from_email</span><span class="o">=</span><span class="s">'contact-form@myapp.com'</span><span class="p">,</span>
            <span class="n">recipient_list</span><span class="o">=</span><span class="p">[</span><span class="n">settings</span><span class="o">.</span><span class="n">LIST_OF_EMAIL_RECIPIENTS</span><span class="p">],</span>
        <span class="p">)</span>
        <span class="k">return</span> <span class="nb">super</span><span class="p">(</span><span class="n">ContactFormView</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">form_valid</span><span class="p">(</span><span class="n">form</span><span class="p">)</span>
</pre></div>
<p>In templates/myapp/email_form.html:</p>
<div class="highlight"><pre>{% extends 'base.html' %}
{% load crispy_forms_tags %}

{% block title %}Send an email{% endblock %}

{% block content %}
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;row&quot;</span><span class="nt">&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;span6&quot;</span><span class="nt">&gt;</span>
            <span class="nt">&lt;h1&gt;</span>Send an email<span class="nt">&lt;/h1&gt;</span>
            {% crispy form form.helper %}
        <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
{% endblock %}

{% block extrajs %}
<span class="nt">&lt;script </span><span class="na">src=</span><span class="s">&quot;{{ STATIC_URL }}js/jquery-1.7.1.min.js&quot;</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">&quot;text/javascript&quot;</span><span class="nt">&gt;</span>
<span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">$</span><span class="p">(</span><span class="s1">'#id_name'</span><span class="p">).</span><span class="nx">focus</span><span class="p">()</span>
<span class="p">});</span>
<span class="nt">&lt;/script&gt;</span>
{% endblock %}
</pre></div>
<div class="section" id="tomorrow-s-blog-post">
<h2>Tomorrow's blog post</h2>
<p>In tomorrow's post I'll show how to add CAPTCHA into your project to help reduce spam messages.</p>
</div>
<div class="section" id="want-to-learn-more">
<h2>Want to learn more?</h2>
<p>If you live in the Los Angeles area and want to learn more about Django, everything from the basics to setting up a Content Management System or E-Commerce system, check out our Django (and <a class="reference external" href="http://python.org">Python</a>) training at <a class="reference external" href="https://academy.cartwheelweb.com">Cartwheel Academy</a>.</p>
</div>]]></description>
    <link><![CDATA[http://pydanny.com/simple-django-email-form-using-cbv.html]]></link>
    <pubDate>2012-05-22 09:30:00</pubDate>
  </item>
</channel>
</rss>

