<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <link>http://mikewatkins.ca/tags/tutorial/</link>
  <atom:link href="http://mikewatkins.ca/tags/tutorial/feeds/rss" type="application/rss+xml" rel="self"/>
  <lastBuildDate>Thu, 22 Jan 2009 23:07:58 GMT</lastBuildDate>
  <title>mike watkins dot ca</title>
  <description>XML Feed for mike watkins dot ca</description>
  <language>en</language>
  <generator>Parlez/0.1</generator>
<item>
  <title>Resty applications in QP, Part III</title>
  <link>http://mikewatkins.ca/2009/01/22/resty-applications-in-qp-part-iii/</link>
  <description><![CDATA[
<div class="document">
<p><strong>Traversing the URI Path in QP Applications</strong></p>
<p>In order to complete the Songs application we should understand how QP's
default traversal mechanism makes it easy to provide a navigable UI for our
objects we want to expose to the web.</p>
<p>In the last article in this series we saw through a <em>hello, world</em> example
that a QP application has two key classes, a <tt class="docutils literal"><span class="pre">SitePublisher</span></tt> and a
<tt class="docutils literal"><span class="pre">SiteDirectory</span></tt>, and that SiteDirectory exposes the <em>root</em> UI of a QP
application. Let's flesh out a HTML interface to go along with the REST API
offered by the Songs application, to include:</p>
<pre class="literal-block">
URI segment     Name    Returns to web browser
(export)
-------------------------------------------------------------
class SiteDirectory
/               index   HTML listing of songs
/new            new     HTML form / creation of new song
/delete         clear   HTML form allowing deletion of all songs
</pre>
<p>The functionality at these URI segments will be provided by SiteDirectory:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SiteDirectory</span><span class="p">(</span><span class="n">Directory</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">get_exports</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="s">&#39;Song List&#39;</span><span class="p">,</span> <span class="s">&#39;This is the root / page of this site.&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;api&#39;</span><span class="p">,</span> <span class="s">&#39;api&#39;</span><span class="p">,</span> <span class="s">&#39;API&#39;</span><span class="p">,</span> <span class="s">&#39;API documentation and entry point&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;new&#39;</span><span class="p">,</span> <span class="s">&#39;new&#39;</span><span class="p">,</span> <span class="s">&#39;New&#39;</span><span class="p">,</span> <span class="s">&#39;Add a song to collection&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;delete&#39;</span><span class="p">,</span> <span class="s">&#39;clear&#39;</span><span class="p">,</span> <span class="s">&#39;Delete&#39;</span><span class="p">,</span> <span class="s">&#39;Delete all songs from collection&#39;</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">index</span><span class="p">:</span><span class="n">xml</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">header</span><span class="p">(</span><span class="s">&#39;Song Database&#39;</span><span class="p">)</span>
        <span class="s">&#39;&lt;h1&gt;Songs&lt;/h1&gt;&#39;</span>
        <span class="s">&#39;&lt;ul&gt;&#39;</span>
        <span class="k">for</span> <span class="n">song</span> <span class="ow">in</span> <span class="n">get_song_db</span><span class="p">()</span><span class="o">.</span><span class="n">itervalues</span><span class="p">():</span>
            <span class="s">&#39;&lt;li&gt;</span><span class="si">%s</span><span class="s">: &lt;a href=&quot;</span><span class="si">%s</span><span class="s">/&quot;&gt;</span><span class="si">%s</span><span class="s">&lt;/a&gt;&lt;/li&gt;&#39;</span> <span class="o">%</span> <span class="p">(</span>
                <span class="n">song</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">song</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">song</span><span class="o">.</span><span class="n">title</span><span class="p">)</span>
        <span class="s">&#39;&lt;/ul&gt;&#39;</span>
        <span class="n">footer</span><span class="p">()</span>

    <span class="c"># ... for the forms examples provided by new/delete</span>
    <span class="c"># read the SongDirectory class at the end of  this article</span>
</pre></div>
<p>What of the API? Thanks to content-negotiation capability provided by the
<tt class="docutils literal"><span class="pre">Resource</span></tt> subclass of <tt class="docutils literal"><span class="pre">Directory</span></tt>, we <em>could</em> intermingle our API
functionality at the same URI as our HTML UI. Emphasis is on the word <em>could</em>
because from this point forward, purely for the sake of clarity in this and
subsequent articles on this theme, I'm going to risk angering the RESTafarian
gods and instead <em>host</em> the entire REST API under the <tt class="docutils literal"><span class="pre">/api/</span></tt> url segment.
To the SiteDirectory class above we'll merely add an attribute and an entry in
<tt class="docutils literal"><span class="pre">get_exports()</span></tt>:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SiteDirectory</span><span class="p">(</span><span class="n">Directory</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">get_exports</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="s">&#39;Song List&#39;</span><span class="p">,</span> <span class="s">&#39;This is the root / page of this site.&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;new&#39;</span><span class="p">,</span> <span class="s">&#39;new&#39;</span><span class="p">,</span> <span class="s">&#39;New&#39;</span><span class="p">,</span> <span class="s">&#39;Add a song to collection&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;delete&#39;</span><span class="p">,</span> <span class="s">&#39;clear&#39;</span><span class="p">,</span> <span class="s">&#39;Delete&#39;</span><span class="p">,</span> <span class="s">&#39;Delete all songs from collection&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;api&#39;</span><span class="p">,</span> <span class="s">&#39;api&#39;</span><span class="p">,</span> <span class="s">&#39;API&#39;</span><span class="p">,</span> <span class="s">&#39;API documentation and entry point&#39;</span><span class="p">)</span>

    <span class="n">api</span> <span class="o">=</span> <span class="n">SongDatabaseResource</span><span class="p">()</span>

    <span class="c"># ...</span>
</pre></div>
<p>Therefore our API will be accessible via the <tt class="docutils literal"><span class="pre">SongDatabaseResource</span></tt> subclass
(<a class="reference external" href="http://mikewatkins.ca/2009/01/18/resty-applications-in-qp/">first discussed here</a>) of <tt class="docutils literal"><span class="pre">Resource</span></tt> and will expose the following:</p>
<pre class="literal-block">
URI      method  accept              Return
-------------------------------------------------------------
class SongDatabaseResource
/api/    GET     application/json    json dict of all songs
/api/    DELETE  application/json    json {'result': 'true'} on success
/api/    POST    application/json    json dict of new song data
</pre>
<p>Architectural style purity aside, there are reasons in the practical world why
one might wish to bury an API, even a REST API, behind a mount point as we've
done. The busy developer with security (or marketing) concerns might want to
only expose the API to authenticated users. Let's do that:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SongDatabaseResource</span><span class="p">(</span><span class="n">Resource</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">get_resources</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">get_publisher</span><span class="p">()</span><span class="o">.</span><span class="n">ensure_signed_in</span><span class="p">()</span>
        <span class="k">yield</span> <span class="n">export</span><span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;__api__&#39;</span><span class="p">)</span> <span class="c"># docs for web browsers</span>
        <span class="k">yield</span> <span class="n">export</span><span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;dump&#39;</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s">&#39;GET&#39;</span><span class="p">,</span> <span class="n">accept</span><span class="o">=</span><span class="s">&#39;application/json&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="n">export</span><span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;new&#39;</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s">&#39;POST&#39;</span><span class="p">,</span> <span class="n">accept</span><span class="o">=</span><span class="s">&#39;application/json&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="n">export</span><span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;clear&#39;</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s">&#39;DELETE&#39;</span><span class="p">,</span> <span class="n">accept</span><span class="o">=</span><span class="s">&#39;application/json&#39;</span><span class="p">)</span>

    <span class="c"># ...</span>
</pre></div>
<p>OK, we sketched out the first <tt class="docutils literal"><span class="pre">/</span></tt> of the HTML UI. How do we traverse to
individual songs?</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SiteDirectory</span><span class="p">(</span><span class="n">Directory</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">get_exports</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="s">&#39;Song List&#39;</span><span class="p">,</span> <span class="s">&#39;This is the root / page of this site.&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;api&#39;</span><span class="p">,</span> <span class="s">&#39;api&#39;</span><span class="p">,</span> <span class="s">&#39;API&#39;</span><span class="p">,</span> <span class="s">&#39;API documentation and entry point&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;new&#39;</span><span class="p">,</span> <span class="s">&#39;new&#39;</span><span class="p">,</span> <span class="s">&#39;New&#39;</span><span class="p">,</span> <span class="s">&#39;Add a song to collection&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;delete&#39;</span><span class="p">,</span> <span class="s">&#39;clear&#39;</span><span class="p">,</span> <span class="s">&#39;Delete&#39;</span><span class="p">,</span> <span class="s">&#39;Delete all songs from collection&#39;</span><span class="p">)</span>

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

    <span class="k">def</span> <span class="nf">_q_lookup</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">component</span><span class="p">):</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">component</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">component</span><span class="p">)</span>
            <span class="n">song</span> <span class="o">=</span> <span class="n">get_song_db</span><span class="p">()</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">component</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">song</span><span class="p">:</span>
                <span class="k">return</span> <span class="n">SongDirectory</span><span class="p">(</span><span class="n">song</span><span class="p">)</span>
        <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
            <span class="c"># None / an empty &#39;&#39; response being returned from _q_lookup</span>
            <span class="c"># will result in 404 not_found being delivered as the response.</span>
            <span class="k">return</span> <span class="bp">None</span>

    <span class="n">api</span> <span class="o">=</span> <span class="n">SongDatabaseResource</span><span class="p">()</span>
</pre></div>
<p>The important mechanism to note here is <tt class="docutils literal"><span class="pre">_q_lookup</span></tt>. The default QP
traversal mechanism (which may easily be changed) traverses Directory
subclasses looking for callables or objects. One can create arbitrarily complex
URI schemes with levels nested many deep, if that turns your crank.</p>
<p>The object traversal approach is a flexible mechanism, quite different than
mapping callables or objects to URIs via regular expressions.  But one could
do that in QP too, if you found a need to. If you need even more flexibility
you can override the <tt class="docutils literal"><span class="pre">Directory</span></tt> class <tt class="docutils literal"><span class="pre">_q_traverse</span></tt> method or dive into
the <tt class="docutils literal"><span class="pre">Publisher</span></tt> itself.</p>
<p>One benefit of this approach is others who may use these classes generally do
not need to concern themselves at all about where in their URI namespace they
deploy these UI components.</p>
<p>The attached file: <a class="reference external" href="http://mikewatkins.ca/2009/01/22/resty-applications-in-qp-part-iii/file/746a54037f9b/">song.qpy</a>, is a QPY template file containing a quick draft of the HTML UI.</p>
<p>This RESTy Songs database example has morphed into something of a QP
<em>howto</em>. For those who just want to see the end result, fear not, I see that
coming around the bend soon. It is time to tie it all together... tomorrow.</p>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:690</guid>
  <pubDate>Thu, 22 Jan 2009 23:07:58 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
  <category>rest</category>
  <category>tutorial</category>
</item>
<item>
  <title>QP and WSGI</title>
  <link>http://mikewatkins.ca/2009/01/21/qp-and-wsgi/</link>
  <description><![CDATA[
<div class="document">
<p>QP doesn't use WSGI itself in the operation of its own built-in web and SCGI
servers, but the framework does make it easy to drive QP applications via
WSGI if you have a need to. Here's a quick how-to.</p>
<p>Exposing the QP application as a WSGI app is simple. Create a driver file
(let's name it <tt class="docutils literal"><span class="pre">runwsgi.py</span></tt>) and place it in your Python path. Myself I prefer to put such files in my QP application's &quot;site&quot; directory.</p>
<div class="highlight"><pre><span class="c"># this is runwsgi.py</span>
<span class="kn">from</span> <span class="nn">qp.lib.site</span> <span class="kn">import</span> <span class="n">Site</span>
<span class="n">site</span> <span class="o">=</span> <span class="n">Site</span><span class="p">(</span><span class="s">&#39;songs&#39;</span><span class="p">)</span>
<span class="n">application</span> <span class="o">=</span> <span class="n">site</span><span class="o">.</span><span class="n">get_publisher</span><span class="p">()</span>
</pre></div>
<p>You can then run a WSGI server (such as <tt class="docutils literal"><span class="pre">Spawning</span></tt>) from the command line:</p>
<pre class="literal-block">
% spawn -t 0 -p 8000 qp.sites.songs.runwsgi.application
</pre>
<p>Or we can extend <tt class="docutils literal"><span class="pre">runwsgi.py</span></tt> to <em>also</em> provide a self-contained WSGI server:</p>
<div class="highlight"><pre><span class="c">#! /usr/bin/env python</span>
<span class="c"># this is runwsgi.py</span>
<span class="kn">from</span> <span class="nn">qp.lib.site</span> <span class="kn">import</span> <span class="n">Site</span>
<span class="n">site</span> <span class="o">=</span> <span class="n">Site</span><span class="p">(</span><span class="s">&#39;songs&#39;</span><span class="p">)</span>
<span class="n">application</span> <span class="o">=</span> <span class="n">site</span><span class="o">.</span><span class="n">get_publisher</span><span class="p">()</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="kn">from</span> <span class="nn">wsgiref.simple_server</span> <span class="kn">import</span> <span class="n">make_server</span>
    <span class="n">host</span><span class="p">,</span> <span class="n">port</span> <span class="o">=</span> <span class="n">site</span><span class="o">.</span><span class="n">get_http_address</span><span class="p">()</span>
    <span class="n">httpd</span> <span class="o">=</span> <span class="n">make_server</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">,</span> <span class="n">application</span><span class="p">)</span>
    <span class="n">hp</span> <span class="o">=</span> <span class="n">httpd</span><span class="o">.</span><span class="n">socket</span><span class="o">.</span><span class="n">getsockname</span><span class="p">()</span>
    <span class="k">print</span><span class="p">(</span><span class="s">&quot;Serving HTTP on </span><span class="si">%s</span><span class="s"> port </span><span class="si">%d</span><span class="s">...&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">hp</span><span class="p">[</span><span class="mf">0</span><span class="p">],</span> <span class="n">hp</span><span class="p">[</span><span class="mf">1</span><span class="p">]))</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">httpd</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>
    <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">&quot;</span><span class="se">\n</span><span class="s">Stopping server(s)&quot;</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">site</span><span class="o">.</span><span class="n">is_durus_running</span><span class="p">():</span>
            <span class="n">site</span><span class="o">.</span><span class="n">stop_durus</span><span class="p">()</span>
</pre></div>
<p>We can execute this directly; the application will use the same host and port
defined in our application's configuration.</p>
<div class="highlight"><pre>% ./runwsgi.py
</pre></div>
<div class="admonition-python-3-compatibility admonition">
<p class="first admonition-title">Python 3 Compatibility</p>
<p>In keeping with my blog's objective of only publishing examples that are compatible with both Python 2.x and 3.x, I need to point out that the QP code presented certainly will run on Python 3.0 but the wsgi servers (spawning and the reference WSGI server) noted will not.</p>
<p class="last">While QP and the rest of its stack is compatible with Python &gt;= 2.4 (yes, that means Python 3.x too), the reference implementation of WSGI supplied with Python 3.0 is broken. As far as I know the only working WSGI server implementation for Python 3 at present is <tt class="docutils literal"><span class="pre">mod_wsgi</span></tt>, <a class="reference external" href="http://code.google.com/p/modwsgi/">available for Apache here</a>.</p>
</div>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:689</guid>
  <pubDate>Wed, 21 Jan 2009 19:59:32 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
  <category>wsgi</category>
  <category>tutorial</category>
</item>
<item>
  <title>Resty applications in QP, Part II</title>
  <link>http://mikewatkins.ca/2009/01/21/resty-applications-in-qp-part-ii/</link>
  <description><![CDATA[
<div class="document">
<p>In this installment we'll take a break from the implementation started in the <a class="reference external" href="http://mikewatkins.ca/2009/01/18/resty-applications-in-qp/">post
previous</a> of a <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> and <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> based <em>RESTy</em> song database application
loosely following the meme which has arisen from Eric Florenzano's <a class="reference external" href="http://www.eflorenzano.com/blog/post/writing-blazing-fast-infinitely-scalable-pure-wsgi/">example
bare-metal WSGI implementation</a> of same. Today I want to point out some QP
features which are useful and perhaps a little unusual.</p>
<div class="contents topic" id="inside">
<p class="topic-title first">Inside</p>
<ul class="simple">
<li><a class="reference internal" href="#basics" id="id3">Basics</a></li>
<li><a class="reference internal" href="#qp-hello-world-prototype" id="id4">QP Hello World Prototype</a></li>
<li><a class="reference internal" href="#qpy-templates" id="id5">QPY Templates</a></li>
<li><a class="reference internal" href="#authentication" id="id6">Authentication</a></li>
</ul>
</div>
<div class="section" id="basics">
<h2><a class="toc-backref" href="#id3">Basics</a></h2>
<p>While QP may not be a <em>bare-metal</em> framework, it also isn't an
<em>mega-framework</em> encapsulating a ton of functionality. The designer's ethos
might well be extracted from the last line in QP's README:</p>
<blockquote class="pull-quote">
The abbreviation &quot;qp&quot; stands for &quot;quantum placet&quot;, the Latin phrase
meaning &quot;as much as you please&quot;.</blockquote>
<p>QP provides basic but solid building blocks for web applications out of the box,
including via its partner package <a class="reference external" href="http://www.mems-exchange.org/software/qpy/">QPY</a> high level protection against XSS
(cross site scripting) attacks and a novel and very fast Python templating
system. You'll also get a user authentication system including form, HTTP
Basic and HTTP Digest authentication.</p>
</div>
<div class="section" id="qp-hello-world-prototype">
<h2><a class="toc-backref" href="#id4">QP Hello World Prototype</a></h2>
<p>QP application's typically minimally consist of a SitePublisher and
SiteDirectory class. SitePublisher contains a configuration dictionary which
can be used for both the framework and your applications. Since we are using
the built-in Durus object database-backed User database for the Songs
application, we'll employ a <tt class="docutils literal"><span class="pre">DurusPublisher</span></tt> and instruct the <tt class="docutils literal"><span class="pre">qp</span></tt> site
management command line utility to start a web and Durus daemon:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SitePublisher</span><span class="p">(</span><span class="n">DurusPublisher</span><span class="p">):</span>

    <span class="n">configuration</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
        <span class="n">durus_address</span><span class="o">=</span><span class="p">(</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="mf">7023</span><span class="p">),</span>
        <span class="n">http_address</span><span class="o">=</span><span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="mf">8023</span><span class="p">),</span>
        <span class="p">)</span>
</pre></div>
<p>The &quot;root directory&quot; of a typical QP application is a class named
SiteDirectory. A <em>hello world</em> application driven by the above publisher would
look like this:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SiteDirectory</span><span class="p">(</span><span class="n">Directory</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">get_exports</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="c"># URI segment exported, method name, crumb, title</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="s">&#39;Home&#39;</span><span class="p">,</span> <span class="s">&#39;Home page of the site&#39;</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&#39;hello, world.&#39;</span>
</pre></div>
<p>That's it.</p>
<p>Starting a QP application using the built-in site management tool
is simple:</p>
<div class="highlight"><pre>% qp -u songs
</pre></div>
<p>QP includes all the facilities for starting and stopping web and other
processes. It uses a multi-process rather than multi-thread model and spawns
new worker processes (configurable) as needed. Multi-CPU / multi-core machines
can eek out significant performance with nothing but the base QP servers; for
a large site typically I'll put the QP application behind an Apache or
lighttpd web daemon (using either a proxy or SCGI configuration), and serve
the static content with those servers. QP can also play in the WSGI space -
look for a quick how-to in the next post.</p>
</div>
<div class="section" id="qpy-templates">
<h2><a class="toc-backref" href="#id5">QPY Templates</a></h2>
<p>Let us now demonstrate one of the cooler or unusual features of QP / QPY -
Python centric templating. Whether this model works for you or not depends a
lot on how you look at code and (x)HTML / text templates. Programming teams
who are also responsible for the site layout may find refreshing the QPY
approach of putting content-in-Python, as opposed to most templating packages
which focus on enabling Python-like languages within text / HTML / XMl
templates.</p>
<p>An example should make things clear. We'll write a method to say hello back to
us n-times based on url parameters <tt class="docutils literal"><span class="pre">age</span></tt> and <tt class="docutils literal"><span class="pre">name</span></tt>, to respond to a query
like:</p>
<pre class="literal-block">
curl http://localhost:8023/?age=3&amp;name=Mary
</pre>
<p>Instead of using <tt class="docutils literal"><span class="pre">return</span></tt> to send a string back to the Publisher, we use a
special notation on our method - <tt class="docutils literal"><span class="pre">:xml</span></tt>:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">qp.pub.common</span> <span class="kn">import</span> <span class="n">get_request</span>

<span class="k">class</span> <span class="nc">SiteDirectory</span><span class="p">(</span><span class="n">Directory</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">index</span><span class="p">:</span><span class="n">xml</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>

        <span class="n">context</span> <span class="o">=</span> <span class="n">get_request</span><span class="p">()</span><span class="o">.</span><span class="n">fields</span>
        <span class="sd">&#39;&#39;&#39;</span>
<span class="sd">        &lt;html&gt;</span>
<span class="sd">        &lt;head&gt;</span>
<span class="sd">            &lt;title&gt;Hello&lt;/title&gt;</span>
<span class="sd">        &lt;/head&gt;</span>
<span class="sd">        &lt;body&gt;</span>
<span class="sd">            &lt;ol&gt;</span>
<span class="sd">        &#39;&#39;&#39;</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="nb">int</span><span class="p">(</span><span class="n">context</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;age&#39;</span><span class="p">,</span> <span class="mf">1</span><span class="p">))):</span>
            <span class="s">&#39;&lt;li&gt;</span><span class="si">%(name)s</span><span class="s">, </span><span class="si">%(age)s</span><span class="s"> years old&lt;/li&gt;&#39;</span> <span class="o">%</span> <span class="n">context</span>
        <span class="sd">&#39;&#39;&#39;</span>
<span class="sd">            &lt;/ol&gt;</span>
<span class="sd">        &lt;/body&gt;</span>
<span class="sd">        &lt;/html&gt;</span>
<span class="sd">        &#39;&#39;&#39;</span>
</pre></div>
<p>When <tt class="docutils literal"><span class="pre">index</span></tt> is called the string literal will be completed and passed back
as a return value. Its a much cleaner looking approach than building up a
string.</p>
<p>The method descriptor <tt class="docutils literal"><span class="pre">:xml</span></tt> is enabled by QPY. There are two such
descriptors provided by QPY, <tt class="docutils literal"><span class="pre">:xml</span></tt> and <tt class="docutils literal"><span class="pre">:str</span></tt>. String literals within
<tt class="docutils literal"><span class="pre">:xml</span></tt> templates are cast as a <em>quote no more</em> type, while variable data passed
to the template (such as the <tt class="docutils literal"><span class="pre">context</span></tt> dictionary in the example) will be
escaped or quoted for safety once and only once as it is included in the template.
<tt class="docutils literal"><span class="pre">:str</span></tt> templates provide no automatic escaping and quoting.</p>
<p>The QPY templating system provides four major benefits:</p>
<ol class="arabic simple">
<li>You already know the language because it is pure Python.</li>
<li>Automatic protection from cross site scripting (XSS) attacks and
other malicious value injection.</li>
<li>Unicode sane and safe, like the rest of the QP stack.</li>
<li>QPY is uncomplicated and very fast.</li>
</ol>
<p>Speaking of Unicode, QP applications treat all text data internally as
Unicode. The default character set is <tt class="docutils literal"><span class="pre">utf-8</span></tt>. Writing QP / QPY applications
to run on either Python 2.x or 3.x requires no special Unicode gymnastics.</p>
<p>In addition, all parts of the QP stack - Durus, QPY and QP itself - are Python
3 compatible, today. QPY is packaged separately from QP to make it accessible
for other templating package authors to employ features such as its quote no
more class and Python extensions.</p>
</div>
<div class="section" id="authentication">
<h2><a class="toc-backref" href="#id6">Authentication</a></h2>
<p>QP's default authentication method is HTTP Digest; this can be changed by
trivially overriding the <tt class="docutils literal"><span class="pre">ensure_signed_in()</span></tt> method of Publisher. For the
SongDatabase API we won't alter the default since <tt class="docutils literal"><span class="pre">Form</span></tt> isn't workable for
a RESTful API, and using <tt class="docutils literal"><span class="pre">Digest</span></tt> over <tt class="docutils literal"><span class="pre">Basic</span></tt> gives us the ability to
offer at least authentication security without using <tt class="docutils literal"><span class="pre">HTTPS</span></tt>.</p>
<p>If we extended our <em>hello, world</em> prototype to provide some more functionality
if you are logged on user, and even more if you are an administrator, it would
look like this:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">qp.pub.common</span> <span class="kn">import</span> <span class="n">get_publisher</span><span class="p">,</span> <span class="n">get_user</span>

<span class="k">class</span> <span class="nc">SiteDirectory</span><span class="p">(</span><span class="n">Directory</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">get_exports</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="c"># URI segment exported, method name, crumb, title</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="s">&#39;Home&#39;</span><span class="p">,</span> <span class="s">&#39;Home page of the site&#39;</span><span class="p">)</span>
        <span class="n">get_publisher</span><span class="p">()</span><span class="o">.</span><span class="n">ensure_signed_in</span><span class="p">()</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;users&#39;</span><span class="p">,</span> <span class="s">&#39;users&#39;</span><span class="p">,</span> <span class="s">&#39;Users&#39;</span><span class="p">,</span> <span class="s">&#39;Pithy title here&#39;</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">get_user</span><span class="p">()</span><span class="o">.</span><span class="n">is_admin</span><span class="p">():</span>
            <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;secrets&#39;</span><span class="p">,</span> <span class="s">&#39;top_secret&#39;</span><span class="p">,</span> <span class="s">&#39;Home&#39;</span><span class="p">,</span> <span class="s">&#39;Secrets&#39;</span><span class="p">,</span> <span class="s">&#39;Something intriguing&#39;</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&#39;hello, world.&#39;</span>

    <span class="k">def</span> <span class="nf">users</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&#39;hello, real user </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="n">get_user</span><span class="p">()</span><span class="o">.</span><span class="n">id</span>

    <span class="k">def</span> <span class="nf">top_secret</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&#39;the password is &quot;orange&quot;. Sssh!&#39;</span>
</pre></div>
<p>In the foregoing example an unauthenticated user will not even be able to
navigate to <tt class="docutils literal"><span class="pre">/users</span></tt> or <tt class="docutils literal"><span class="pre">/secrets</span></tt>. An authenticated user who isn't
also a site administrator will not be able to navigate to <tt class="docutils literal"><span class="pre">/secrets</span></tt>.</p>
<p>One could put the authentication checks within an exported method instead, but
the nice thing about using the <tt class="docutils literal"><span class="pre">get_exports</span></tt> mechanism is menu and crumb
generation routines also use the data yielded, so putting auth checks there is
a benefit if you prefer not to show your site users menus they don't currently
have authorization to access.</p>
<p>Coming up next, a quick note on running QP as a WSGI application, and we'll
get back to the Song application.</p>
</div>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:688</guid>
  <pubDate>Wed, 21 Jan 2009 19:42:32 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
  <category>rest</category>
  <category>tutorial</category>
</item>
<item>
  <title>Resty applications in QP</title>
  <link>http://mikewatkins.ca/2009/01/18/resty-applications-in-qp/</link>
  <description><![CDATA[
<div class="document">
<p>There have of late been a number of articles posted to the Pythonosphere
describing approaches to delivering a REST-like or RESTful API. In keeping
with the meme Eric Florenzano started by posting his bare-metal no-framework
WSGI approach, to the growing list I'll add an entry for the <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP web
framework</a> and <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus object database</a> tag-team.</p>
<p>Eric Florenzano's <a class="reference external" href="http://www.eflorenzano.com/blog/post/writing-blazing-fast-infinitely-scalable-pure-wsgi/">deliberately minimalist WSGI application</a> illustrating a
bare metal WSGI application with RESTful behaviour has drawn out from other
Python web application framework communities a number of useful comparisons:</p>
<ol class="arabic simple">
<li>Christian Wyglendowski's entry using <a class="reference external" href="http://blog.dowski.com/2009/01/08/http-utilities-with-cherrypy/">cherrypy</a></li>
<li>Tim Parkin's <a class="reference external" href="http://dev.timparkin.co.uk/2009/01/happy-medium-from-wsgi-to-cherrypy.html">restish approach</a></li>
<li><a class="reference external" href="http://faassen.n--tree.net/blog/view/weblog/2009/01/10/0">Grok showing real object persistence</a> by Martijn Faasen.</li>
<li>A <a class="reference external" href="http://dev.timparkin.co.uk/2009/01/werkzeug-and-werkzeugish-example.html">Werkzeug solution</a> also by Tim Parkin.</li>
<li>Carlos de la Guardia <a class="reference external" href="http://blog.delaguardia.com.mx/index.php?op=ViewArticle&amp;articleId=119&amp;blogId=1">provides a solution via repoze.bfg</a>,
which, like Grok, shows how Zope3 technologies can be used.</li>
</ol>
<p>I particularly identify with the CherryPy solution because QP's default
traversal mechanism feels similar - both use an object publishing metaphor that relies on traversal of classes rather than a <tt class="docutils literal"><span class="pre">routes</span></tt> or url regular expression approach.</p>
<p>QP inherited its traversal approach from its older cousin <a class="reference external" href="http://quixote.ca/">Quixote</a>, which in turn borrowed the object publishing metaphor from Zope oh so many years ago. Quixote was always a minimalistic framework without strong opinions; QP is a little more opinionated. While you can quite easily break away from QP's intentional affinity for Durus for object persistence, out of the box QP provides user and session handling all backed by the Durus object database. Despite offering much more capability than Quixote by way of the defaults and conventions chosen, QP, QPY (the modern equivalent to Quixote's PTL templating system) and Durus are small enough to be read through in a single sitting with ease.</p>
<p>Martijn's solution (and any Zope-solution by inference) is also somewhat
familiar to me because QP's default object persistence method is the Durus
Python object database. Durus can best be thought of as a simpler ZODB
(and ZEO) work-a-like.</p>
<p>Since Eric's goal was to see how many requests he could churn out of a
bare-metal WSGI application, here are some <em>relative</em> numbers on my
workstation, an old desktop running FreeBSD on a single CPU single-core. Even
on this suboptimal box the QP <tt class="docutils literal"><span class="pre">songs</span></tt> app can respond to several hundred
requests per second.</p>
<p>Relative Performance:</p>
<pre class="literal-block">
%       Application
---     -----------
100     Eric's bare metal WSGI dict-driven example as baseline
58      CherryPy read from dict-driven example, Spawning server
61      QP, read from dict-driven &quot;database&quot; example, QP native server
60      QP, read from Durus persistent object database, QP native server
42      QP, write to Durus persistent object database, QP native server
65      QP, same app/Durus, read, simple WSGI server
50      QP, same app/Durus, read, Spawning server
59      Repoze.bfd, Spawning server, based on numbers published by Carlos
??      Grok, identified by Martijn as being appox. 50% of Eric's app on
        his machine
</pre>
<p>Certainly in my own experience raw performance has never been an issue thus I doubt I would ever want to trade away a framework I was comfortable with to
write bare metal WSGI apps. Following along with the &quot;song&quot; meme,
I'll show in the next couple of posts one approach to structuring a
QP application, and some background information on QP and Durus.</p>
<div class="section" id="song-and-song-database-objects">
<h2>Song and Song Database Objects</h2>
<p>Let's see if we can't kill two birds with one stone and show a slightly
beefier version of Eric's simple dict-based &quot;database&quot; using nothing but plain
Python. I've added a Counter object for use in counting &quot;I heard it&quot; events
but also for use as a key generator for our &quot;database&quot;, much like an identity
column in a SQL database.</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">Counter</span><span class="p">(</span><span class="nb">object</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="bp">self</span><span class="o">.</span><span class="n">count</span> <span class="o">=</span> <span class="mf">0</span>

    <span class="k">def</span> <span class="nf">next</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">count</span> <span class="o">+=</span> <span class="mf">1</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">count</span>

<span class="k">class</span> <span class="nc">Song</span><span class="p">(</span><span class="nb">object</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="n">title</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="bp">None</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">title</span> <span class="o">=</span> <span class="n">title</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="n">Counter</span><span class="p">()</span>

<span class="k">class</span> <span class="nc">SongDatabase</span><span class="p">(</span><span class="nb">dict</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="bp">self</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="n">Counter</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">song</span><span class="p">):</span>
        <span class="n">song</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">counter</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
        <span class="bp">self</span><span class="p">[</span><span class="n">song</span><span class="o">.</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">song</span>
</pre></div>
<p>Later in this article with barely any additional code we'll convert these to be
full-fledged persistent Python objects. Peek ahead and you'll find: two import lines, class inheritance changes, and one trivial new line of actual code.</p>
<p>With this &quot;database&quot; in place lets write a class to expose our
database as a web service. Later we'll add some other features like
self-documentation and an HTML UI for humans.</p>
<p>I don't want to do my dispatching based on either the exported
<tt class="docutils literal"><span class="pre">name</span></tt> or the request method alone, so with a few lines of code I
implemented a more generalized Resource class, extending QP's default
<tt class="docutils literal"><span class="pre">Directory</span></tt> class.  QP's default traversal mechanism is being bent
slightly to take into account the HTTP request method and accept
header.</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SongDatabaseResource</span><span class="p">(</span><span class="n">Resource</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">get_resources</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">yield</span> <span class="n">export</span><span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;dump&#39;</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s">&#39;GET&#39;</span><span class="p">,</span> <span class="n">accept</span><span class="o">=</span><span class="s">&#39;application/json&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="n">export</span><span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;new&#39;</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s">&#39;POST&#39;</span><span class="p">,</span> <span class="n">accept</span><span class="o">=</span><span class="s">&#39;application/json&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="n">export</span><span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;clear&#39;</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s">&#39;DELETE&#39;</span><span class="p">,</span> <span class="n">accept</span><span class="o">=</span><span class="s">&#39;application/json&#39;</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">dump</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        curl  -X GET -H &#39;Accept: application/json&#39; http://127.0.0.1:8023/api/</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">data</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="k">for</span> <span class="n">song</span> <span class="ow">in</span> <span class="n">get_song_db</span><span class="p">()</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="n">data</span><span class="p">[</span><span class="n">song</span><span class="o">.</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="n">song</span><span class="o">.</span><span class="n">key</span><span class="p">,</span>
                               <span class="n">title</span><span class="o">=</span><span class="n">song</span><span class="o">.</span><span class="n">title</span><span class="p">,</span>
                               <span class="n">count</span><span class="o">=</span><span class="n">song</span><span class="o">.</span><span class="n">counter</span><span class="o">.</span><span class="n">count</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">clear</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        curl  -X DELETE -H &#39;Accept: application/json&#39; http://127.0.0.1:8023/api/</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">songs</span> <span class="o">=</span> <span class="n">get_song_db</span><span class="p">()</span>
        <span class="n">songs</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
        <span class="n">songs</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="n">Counter</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">new</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        Example:</span>
<span class="sd">            curl  -X POST -d &#39;{&quot;title&quot;:&quot;Walking Contradiction&quot;}&#39; \</span>
<span class="sd">                  -H &quot;Content-type: application/json&quot; \</span>
<span class="sd">                  -H &#39;Accept: application/json&#39; http://127.0.0.1:8023/api/</span>
<span class="sd">            Returns:</span>
<span class="sd">                {&quot;count&quot;: 0, &quot;id&quot;: 3, &quot;title&quot;: &quot;Walking Contradiction&quot;}</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">data</span> <span class="o">=</span> <span class="n">get_request</span><span class="p">()</span><span class="o">.</span><span class="n">read_body</span><span class="p">()</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
        <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
            <span class="n">get_publisher</span><span class="p">()</span><span class="o">.</span><span class="n">respond</span><span class="p">(</span>
                <span class="s">&quot;Bad Request&quot;</span><span class="p">,</span> <span class="s">&quot;Malformed json data </span><span class="si">%r</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">data</span><span class="p">,</span> <span class="n">status</span><span class="o">=</span><span class="mf">400</span><span class="p">)</span>
        <span class="n">song</span> <span class="o">=</span> <span class="n">Song</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;title&#39;</span><span class="p">))</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">get_song_db</span><span class="p">()</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">song</span><span class="p">)</span>
        <span class="k">except</span> <span class="ne">ValueError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span>
            <span class="n">get_publisher</span><span class="p">()</span><span class="o">.</span><span class="n">respond</span><span class="p">(</span><span class="s">&quot;Bad Request&quot;</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">),</span> <span class="n">status</span><span class="o">=</span><span class="mf">400</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="n">song</span><span class="o">.</span><span class="n">key</span><span class="p">,</span>
                               <span class="n">title</span><span class="o">=</span><span class="n">song</span><span class="o">.</span><span class="n">title</span><span class="p">,</span>
                               <span class="n">count</span><span class="o">=</span><span class="n">song</span><span class="o">.</span><span class="n">counter</span><span class="o">.</span><span class="n">count</span><span class="p">))</span>
</pre></div>
<p>I've added a little more meat to the basic application meme but
hopefully not so much that the plot is lost.</p>
<p>So far we have a web service or api exposed at the logial root of our
web application. The &quot;database&quot; isn't persistent as yet, so lets fix
that now with a couple of imports, one line of new code, and a change
from the default Python <tt class="docutils literal"><span class="pre">object</span></tt> base class to persistent versions
of same. With these minor changes our objects are now full partners
in the Durus object database. Those familiar with ZODB will certainly
recognize this pattern right away.</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">durus.persistent</span> <span class="kn">import</span> <span class="n">PersistentObject</span>
<span class="kn">from</span> <span class="nn">durus.persistent_dict</span> <span class="kn">import</span> <span class="n">PersistentDict</span>

<span class="c"># persistent Python object              # regular volatile Python objects</span>
<span class="k">class</span> <span class="nc">Counter</span><span class="p">(</span><span class="n">PersistentObject</span><span class="p">):</span>        <span class="c">#   class Counter(object):</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="c">#       def __init__(self):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">count</span> <span class="o">=</span> <span class="mf">0</span>                  <span class="c">#           self.count = 0</span>

    <span class="k">def</span> <span class="nf">next</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>                     <span class="c">#       def next(self):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">count</span> <span class="o">+=</span> <span class="mf">1</span>                 <span class="c">#           self.count += 1</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">count</span>               <span class="c">#           return self.count</span>

<span class="k">class</span> <span class="nc">Song</span><span class="p">(</span><span class="n">PersistentObject</span><span class="p">):</span>           <span class="c">#   class Song(object):</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="n">title</span><span class="p">):</span>          <span class="c">#       def __init__(self, title):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="bp">None</span>                 <span class="c">#           self.key = None</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">title</span> <span class="o">=</span> <span class="n">title</span>              <span class="c">#           self.title = title</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="n">Counter</span><span class="p">()</span>        <span class="c">#           self.counter = Counter()</span>

<span class="k">class</span> <span class="nc">SongDatabase</span><span class="p">(</span><span class="n">PersistentDict</span><span class="p">):</span>     <span class="c">#   class SongDatabase(dict):</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="c">#       def __init__(self):</span>
        <span class="n">PersistentDict</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>   <span class="c">#           self.counter = Counter()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">counter</span> <span class="o">=</span> <span class="n">Counter</span><span class="p">()</span>
                                        <span class="c">#       def add(self, song):</span>
    <span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">song</span><span class="p">):</span>                <span class="c">#           song.key = self.counter.next()</span>
        <span class="n">song</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">counter</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>  <span class="c">#           self[song.key] = song</span>
        <span class="bp">self</span><span class="p">[</span><span class="n">song</span><span class="o">.</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">song</span>
</pre></div>
<p>In my next post on this theme we'll implement the rest of the
SongDatabaseResource / SongResource RESTful API and some HTML UI for
humans, and I'll put all the code up and a live instance for a
while too.</p>
</div>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:686</guid>
  <pubDate>Sun, 18 Jan 2009 23:01:02 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
  <category>rest</category>
  <category>tutorial</category>
</item>
<item>
  <title>Python 2 and 3: Metaclasses</title>
  <link>http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/</link>
  <description><![CDATA[
<div class="document">
<p>Carrying on with <a class="reference external" href="/2008/11/27/python-2-to-3-bridging-the-gap/">Python 2 to 3: Bridging the Gap</a>, in this instalment lets cover one of the potentially thorny language changes in Python 3 - the new syntax for employing  <em>metaclasses</em>.</p>
<div class="contents topic" id="inside">
<p class="topic-title first">Inside</p>
<ul class="simple">
<li><a class="reference internal" href="#defining-the-metaclass" id="id11">Defining the metaclass</a></li>
<li><a class="reference internal" href="#using-the-metaclass-in-python-2-x" id="id12">Using the metaclass in Python 2.x</a></li>
<li><a class="reference internal" href="#using-the-metaclass-in-python-3-x" id="id13">Using the metaclass in Python 3.x</a></li>
<li><a class="reference internal" href="#using-the-metaclass-in-python-2-x-and-3-x" id="id14">Using the metaclass in Python 2.x <em>and</em> 3.x</a></li>
<li><a class="reference internal" href="#ok-prove-it" id="id15">Ok, Prove it</a></li>
<li><a class="reference internal" href="#further-reading-on-metaclasses" id="id16">Further reading on metaclasses</a></li>
<li><a class="reference internal" href="#and-now-for-something-completely-different" id="id17">And now for something completely different</a></li>
</ul>
</div>
<p>Syntax changes in the language are especially problematic as one or the other version simply won't know how to compile your code. Fortunately there is a clean solution for implementing metaclasses in both 2.x and 3.x, <em>with the same source</em>. If pressed for time, <a class="reference external" href="/2008/11/29/python-2-and-3-metaclasses/#using-the-metaclass-in-python-2-x-and-3-x">skip ahead for the solution</a>; there is also a <a class="reference external" href="/2008/11/29/python-2-and-3-metaclasses/file/3f412722e316/">source code file attached</a> to this post which encompasses all that is discussed.</p>
<p>I've wrapped this discussion around a working example - <a class="reference external" href="http://www.youtube.com/view_play_list?p=CDFEA6D52E5CC0EC">Monty Python</a> inspired of course - of a basic metaclass which might be helpful for those who haven't had any exposure to the concept yet.</p>
<div class="section" id="defining-the-metaclass">
<h2><a class="toc-backref" href="#id11">Defining the metaclass</a></h2>
<p>The definition of a metaclass remains the same in both Python 2 and 3. Here is a possibly topical example (if you like old British humour):</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SillyWalksMetaClass</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    A metaclass describing a class that acts as a singleton and provides a</span>
<span class="sd">    registry of funny walking styles, something no Monty Python fan should</span>
<span class="sd">    be without.</span>
<span class="sd">    &quot;&quot;&quot;</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="n">class_name</span><span class="p">,</span> <span class="n">bases</span><span class="p">,</span> <span class="n">namespace</span><span class="p">):</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s">&#39;walk_types&#39;</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">walk_types</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">walk_types</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__name__</span>

    <span class="k">def</span> <span class="nf">get_walks</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="sd">&quot;&quot;&quot;Returns a list ordered by the class name&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">sorted</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">walk_types</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">__name__</span><span class="p">)</span>
</pre></div>
<p>All in all fairly straightforward. Due to what we are doing in the constructor method this class will act as a singleton - more on that later. First lets deal with using the metaclass in both 2.x and 3.x versions of Python and then look at the simple cross version solution.</p>
</div>
<div class="section" id="using-the-metaclass-in-python-2-x">
<h2><a class="toc-backref" href="#id12">Using the metaclass in Python 2.x</a></h2>
<p>In Python 2.x you base your metaclass defined class by using a special attribute called <tt class="docutils literal"><span class="pre">__metaclass</span></tt>:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SillyWalk</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Subclasses implement a silly walk of stunning sillyness</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="n">__metaclass__</span> <span class="o">=</span> <span class="n">SillyWalksMetaClass</span>
</pre></div>
<p>Creating a subclass of our new <tt class="docutils literal"><span class="pre">SillyWalk</span> <span class="pre">type</span></tt> is simple:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">LurchAndJump</span><span class="p">(</span><span class="n">SillyWalk</span><span class="p">):</span>
    <span class="k">pass</span>
</pre></div>
</div>
<div class="section" id="using-the-metaclass-in-python-3-x">
<h2><a class="toc-backref" href="#id13">Using the metaclass in Python 3.x</a></h2>
<p>Here's a potential <em>gotchya</em> when migrating code to Python 3 - while the <tt class="docutils literal"><span class="pre">__metaclass__</span></tt> attribute remains valid, it does absolutely nothing. One assumes your unit tests will have picked up on any future, ahem, oversight, but forewarned is forearmed. In Python 3 we dispense with the magic <tt class="docutils literal"><span class="pre">__metaclass__</span></tt> attribute and instead the class definition syntax grows a keyword ability:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SillyWalk</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">SillyWalksMetaClass</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Subclasses implement a silly walk of stunning sillyness</span>
<span class="sd">    &quot;&quot;&quot;</span>
</pre></div>
<p><em>(Of course you create a subclass in exactly the same way as you would in Python 2.x)</em></p>
<p>I like this just fine, except for the fact that the Python 2.x compiler will spit up all over you if you have this syntax sprinkled in your hoped-to-be cross compatible application. Because <strong>Python 3 introduces a syntax change</strong> (one which Python 2 knows nothing about) you can't simply surround the class definition in a <tt class="docutils literal"><span class="pre">if</span> <span class="pre">sys.version</span> <span class="pre">&lt;</span> <span class="pre">'3':</span></tt> block.</p>
<p>But never fear, there has always been an approach and its dead simple.</p>
</div>
<div class="section" id="using-the-metaclass-in-python-2-x-and-3-x">
<h2><a class="toc-backref" href="#id14">Using the metaclass in Python 2.x <em>and</em> 3.x</a></h2>
<p>What we need is a method which works for both Python 2 and 3 and the solution is:</p>
<div class="highlight"><pre><span class="n">SillyWalk</span> <span class="o">=</span> <span class="n">SillyWalksMetaClass</span><span class="p">(</span><span class="s">&#39;SillyWalk&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nb">object</span><span class="p">,</span> <span class="p">),</span> <span class="p">{})</span>

<span class="c"># That&#39;s it. Really.</span>
</pre></div>
<p>Yes, that's all there is to it. Want to know more? I've included a bibliography - in particular have a look at Michele Simionato's recent articles. I wish I had as I was puzzling this out, as he provides the answer (without highlighting it as a cross-version solution mind you) in the first several paragraphs of part 1.</p>
<p>Digging a little deeper we see the answer was always hiding in front of us, as is frequently the case. Fire up your interpreters!</p>
<div class="highlight"><pre><span class="o">%</span> <span class="n">python3</span><span class="o">.</span><span class="mf">0</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">help</span><span class="p">(</span><span class="nb">type</span><span class="p">)</span>
<span class="n">Help</span> <span class="n">on</span> <span class="k">class</span> <span class="nc">type</span> <span class="ow">in</span> <span class="n">module</span> <span class="n">builtins</span><span class="p">:</span>

<span class="k">class</span> <span class="nc">type</span><span class="p">(</span><span class="nb">object</span><span class="p">)</span>
 <span class="o">|</span>  <span class="nb">type</span><span class="p">(</span><span class="nb">object</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">the</span> <span class="nb">object</span><span class="s">&#39;s type</span>
 <span class="o">|</span>  <span class="nb">type</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">bases</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">a</span> <span class="n">new</span> <span class="nb">type</span>
 <span class="o">|</span> <span class="o">...</span>
</pre></div>
<p>The answer was there all along: <tt class="docutils literal"><span class="pre">type(name,</span> <span class="pre">bases,</span> <span class="pre">dict)</span> <span class="pre">-&gt;</span> <span class="pre">a</span> <span class="pre">new</span> <span class="pre">type</span></tt> which is exactly what we want out of our <tt class="docutils literal"><span class="pre">SillyWalksMetaClass</span></tt> which, by the way, has the following properties:</p>
<ol class="arabic simple">
<li>It acts as a singleton</li>
<li>It provides a 'registry' of sorts - you can imagine building a plugin registry or some such thing with a similar object.</li>
</ol>
<p>Lets see SillyWalks in all its glory:</p>
<div class="highlight"><pre><span class="n">SillyWalk</span> <span class="o">=</span> <span class="n">SillyWalksMetaClass</span><span class="p">(</span><span class="s">&#39;SillyWalk&#39;</span><span class="p">,</span> <span class="p">(</span><span class="nb">object</span><span class="p">,</span> <span class="p">),</span> <span class="p">{})</span>

<span class="c"># As you see, it was only a flesh wound. We have a simple</span>
<span class="c"># and clean approach for metaclasses for both Python 2 and</span>
<span class="c"># 3.</span>

<span class="c"># Subclassing remains the same for Python 2.x and Python 3+,</span>
<span class="c"># lets create four favorite silly walks:</span>

<span class="k">class</span> <span class="nc">Skip</span><span class="p">(</span><span class="n">SillyWalk</span><span class="p">):</span>
    <span class="k">pass</span>

<span class="k">class</span> <span class="nc">LurchAndSkip</span><span class="p">(</span><span class="n">SillyWalk</span><span class="p">):</span>
    <span class="k">pass</span>

<span class="k">class</span> <span class="nc">CleeseSpecial</span><span class="p">(</span><span class="n">SillyWalk</span><span class="p">):</span>
    <span class="s">&#39;The quintessential silly walk&#39;</span>

<span class="k">class</span> <span class="nc">HopWeaveLurchShudder</span><span class="p">(</span><span class="n">SillyWalk</span><span class="p">):</span>
    <span class="k">pass</span>

<span class="c"># got all four?</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">SillyWalk</span><span class="o">.</span><span class="n">get_walks</span><span class="p">())</span> <span class="o">==</span> <span class="mf">4</span>
<span class="c"># right then, lets have a look</span>
<span class="k">print</span><span class="p">(</span><span class="s">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">walk</span><span class="p">)</span> <span class="k">for</span> <span class="n">walk</span> <span class="ow">in</span> <span class="n">SillyWalk</span><span class="o">.</span><span class="n">get_walks</span><span class="p">()]))</span>
<span class="c"># Being a singleton, you&#39;d expect the following to be identical:</span>
<span class="k">print</span><span class="p">(</span><span class="s">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">walk</span><span class="p">)</span> <span class="k">for</span> <span class="n">walk</span> <span class="ow">in</span> <span class="n">LurchAndSkip</span><span class="o">.</span><span class="n">get_walks</span><span class="p">()]))</span>
<span class="c"># and it is...</span>
<span class="k">assert</span> <span class="n">SillyWalk</span><span class="o">.</span><span class="n">get_walks</span><span class="p">()</span> <span class="o">==</span> <span class="n">HopWeaveLurchShudder</span><span class="o">.</span><span class="n">get_walks</span><span class="p">()</span>
</pre></div>
</div>
<div class="section" id="ok-prove-it">
<h2><a class="toc-backref" href="#id15">Ok, Prove it</a></h2>
<div class="highlight"><pre><span class="nv">$ </span>python3.0 meta2and3.py
CleeseSpecial, HopWeaveLurchShudder, LurchAndSkip, Skip
<span class="nv">$ </span>python2.6 meta2and3.py
CleeseSpecial, HopWeaveLurchShudder, LurchAndSkip, Skip
<span class="nv">$ </span>python2.5 meta2and3.py
CleeseSpecial, HopWeaveLurchShudder, LurchAndSkip, Skip
</pre></div>
</div>
<div class="section" id="further-reading-on-metaclasses">
<h2><a class="toc-backref" href="#id16">Further reading on metaclasses</a></h2>
<ul class="simple">
<li><a class="reference external" href="http://www.artima.com/weblogs/viewpost.jsp?thread=236234">Metaclasses in Python 3.0 [1 of 2]</a>, Michele Simionato, August 2008</li>
<li><a class="reference external" href="http://www.artima.com/weblogs/viewpost.jsp?thread=236260">Metaclasses in Python 3.0 [2 of 2]</a>, Michele Simionato, August 2008</li>
<li><a class="reference external" href="http://www.ibm.com/developerworks/linux/library/l-pymeta.html?S_TACT=105AGX03&amp;S_CMP=ART">Metaclass programming in Python (3 part series)</a>, Mertz &amp; Simionato, 2003</li>
<li><a class="reference external" href="http://docs.python.org/reference/datamodel.html#customizing-class-creation">Python 2.6: Customizing Class Creation</a>, Python 2.x Documentation</li>
<li><a class="reference external" href="http://docs.python.org/dev/3.0/reference/datamodel.html#customizing-class-creation">Python 3.0: Customizing Class Creation</a>, Python 3.0 Documentation</li>
<li><a class="reference external" href="http://www.python.org/dev/peps/pep-3115/">Metaclasses in Python 3000</a>, Python PEP 3115</li>
</ul>
</div>
<div class="section" id="and-now-for-something-completely-different">
<h2><a class="toc-backref" href="#id17">And now for something completely different</a></h2>
<div class="figure">
<a class="reference external image-reference" href="http://www.youtube.com/watch?v=9ZlBUglE6Hc"><img alt="http://64.21.147.48/tv-20081128-204328.gif" src="http://64.21.147.48/tv-20081128-204328.gif" /></a>
<p class="caption"><em>Click for a classic, very silly, youtube video. Go on, you know you want to!</em></p>
</div>
</div>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:657</guid>
  <pubDate>Sat, 29 Nov 2008 04:45:46 GMT</pubDate>
  <category>python</category>
  <category>tutorial</category>
</item>
<item>
  <title>Python Web Application Diary, Part Seven</title>
  <link>http://mikewatkins.ca/2007/06/20/python-web-application-diary-part-seven/</link>
  <description><![CDATA[
<div class="document">
<p><strong>User interface handling in QP</strong></p>
<p>In <a class="reference external" href="/tags/python/2007-06-08-08-44.html">part six</a> of <em>Python Web Application Diary</em> we looked at data persistence
using <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> and wrote <a class="reference external" href="http://www.mems-exchange.org/software/sancho/">Sancho</a> unit tests and a skeleton <a class="reference external" href="http://pyblosxom.sourceforge.net/">Pyblosxom</a> migration
tool. Today we'll extend the basic UI created in <a class="reference external" href="/tags/python/2007-06-06-11-51.html">part five</a> for our Entry
object, and we'll create a base UI for the Journal object too. At that point
we'll be able to wire our new <tt class="docutils literal"><span class="pre">JournalDirectory</span></tt> into <tt class="docutils literal"><span class="pre">SiteDirectory</span></tt> (also
referenced in <a class="reference external" href="/tags/python/2007-06-06-11-51.html">part five</a>) - a QP application's &quot;master controller&quot; - which
will allow us to start publishing previously created journal entries to the
web.</p>
<div class="section" id="journaldirectory">
<h2>JournalDirectory</h2>
<p>I find it useful to map out the URL design for a set of related objects and
then start to work on the UI. In <a class="reference external" href="/tags/python/2007-06-06-11-51.html">part five</a> we did this for <tt class="docutils literal"><span class="pre">EntryUI</span></tt>.
Lets get to work on the UI 'container' for our Entries, <tt class="docutils literal"><span class="pre">JournalDirectory</span></tt>.
In this first cut we'll implement enough to display a list of recent entries
and put stubs in place for Atom and RSS feeds.</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">JournalDirectory</span><span class="p">(</span><span class="n">Directory</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    This class provides the functionality to display recent entries,</span>
<span class="sd">    to navigate to a specific entry, and to present RSS and Atom feeds.</span>

<span class="sd">    Our application urls for this UI component will be:</span>

<span class="sd">    ../             &quot;index&quot; or recent entries</span>
<span class="sd">    ../1234/        calls the EntryUI &quot;index&quot; method</span>
<span class="sd">    ../new          create a new Entry</span>
<span class="sd">    ../index.rss</span>
<span class="sd">    ../index.xml</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="nf">get_exports</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;index.rss&#39;</span><span class="p">,</span> <span class="s">&#39;rss&#39;</span><span class="p">,</span> <span class="s">&#39;RSS&#39;</span><span class="p">,</span> <span class="s">&#39;RSS feed for this journal&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;index.xml&#39;</span><span class="p">,</span> <span class="s">&#39;atom&#39;</span><span class="p">,</span> <span class="s">&#39;Atom&#39;</span><span class="p">,</span> <span class="s">&#39;Atom feed for this journal&#39;</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="n">journal</span><span class="p">):</span>
        <span class="n">require</span><span class="p">(</span><span class="n">journal</span><span class="p">,</span> <span class="n">Journal</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">journal</span> <span class="o">=</span> <span class="n">journal</span>

    <span class="k">def</span> <span class="nf">index</span> <span class="p">[</span><span class="n">html</span><span class="p">]</span> <span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">title</span> <span class="o">=</span> <span class="s">&quot;</span><span class="si">%s</span><span class="s">&#39;s journal&quot;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">journal</span><span class="o">.</span><span class="n">get_name</span><span class="p">()</span>
        <span class="n">header</span><span class="p">(</span><span class="n">title</span><span class="p">)</span>
        <span class="s">&#39;&lt;p&gt;This is the journal of &#39;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">journal</span><span class="o">.</span><span class="n">get_name</span><span class="p">()</span>
        <span class="s">&#39;&lt;/p&gt;&#39;</span>
        <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">journal</span><span class="o">.</span><span class="n">get_recent_entries</span><span class="p">(</span><span class="n">count</span><span class="o">=</span><span class="mf">10</span><span class="p">):</span>
            <span class="s">&#39;&lt;p&gt;</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">&lt;/p&gt;&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">get_text</span><span class="p">()</span><span class="o">.</span><span class="n">get_format</span><span class="p">(),</span>
                                 <span class="n">href</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">key</span><span class="p">),</span><span class="n">e</span><span class="o">.</span><span class="n">get_title</span><span class="p">()))</span>
        <span class="n">footer</span><span class="p">(</span><span class="n">title</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">new</span> <span class="p">[</span><span class="n">html</span><span class="p">]</span> <span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s">&#39; not implemented &#39;</span>

    <span class="n">atom</span> <span class="o">=</span> <span class="n">rss</span> <span class="o">=</span> <span class="n">new</span>
</pre></div>
<p>Looking at the code above it you can see that we've provided no way of
navigating to individual entries. In <tt class="docutils literal"><span class="pre">index</span></tt> we've generated links which
look like this:</p>
<pre class="literal-block">
&lt;a href=&quot;./1234&quot;&gt;Some title&lt;/a&gt;
</pre>
<p>What we've not done is provide a way of resolving that part of the URL path.
Lets say for example we have a site:</p>
<pre class="literal-block">
http://mikewatkins.ca/blog
</pre>
<p>With entries:</p>
<pre class="literal-block">
http://mikewatkins.ca/blog/1234
http://mikewatkins.ca/blog/3456
</pre>
<p>How does the QP application resolve these paths?</p>
</div>
<div class="section" id="q-lookup">
<h2>_q_lookup</h2>
<p>Unlike some web application frameworks which use regular expressions to map
URL namespaces to objects/methods or functions, QP uses the concept of object
publishing via object traversal. We've seen how a UI object that exposes
methods can be called; <tt class="docutils literal"><span class="pre">_q_lookup</span></tt> provides us the ability to return
&quot;objects&quot;. Lets write a <tt class="docutils literal"><span class="pre">_q_lookup</span></tt> method for <tt class="docutils literal"><span class="pre">JournalDirectory</span></tt> that
returns an <tt class="docutils literal"><span class="pre">EntryUI</span></tt> object for a specific journal <tt class="docutils literal"><span class="pre">Entry</span></tt>.</p>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">_q_lookup</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">component</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">key</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">component</span><span class="p">)</span>
    <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">not_found</span><span class="p">(</span><span class="s">&#39;</span><span class="si">%r</span><span class="s"> is not a valid journal entry identifier.&#39;</span> <span class="o">%</span> <span class="n">component</span><span class="p">)</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">entry</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">journal</span><span class="o">.</span><span class="n">get_entry</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
    <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">not_found</span><span class="p">(</span><span class="s">&#39;</span><span class="si">%r</span><span class="s"> was not found.&#39;</span> <span class="o">%</span> <span class="n">key</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">EntryUI</span><span class="p">(</span><span class="n">entry</span><span class="p">)</span>
</pre></div>
<p>At this point we have working <tt class="docutils literal"><span class="pre">JournalDirectory</span></tt> and <tt class="docutils literal"><span class="pre">EntryUI</span></tt> objects.
Lets now replace our temporary demonstration code in the applications master
controller with a connection to our <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> database and real data.</p>
<p>As you might imagine, with this object / UI pattern it would be easy to add
support for multiple journals. Objects and their corresponding UI might look
like:</p>
<pre class="literal-block">
Object              UI
--------------------------------------------
Entry               EntryUI
Journal             JournalDirectory
JournalDatabase     JournalDatabaseDirectory
</pre>
</div>
<div class="section" id="wiring-up-the-application">
<h2>Wiring up the application</h2>
<p>For simplicities sake, we are going to first wire up our <tt class="docutils literal"><span class="pre">JournalDirectory</span></tt>
to <tt class="docutils literal"><span class="pre">SiteDirectory</span></tt> which we last talked about in conjunction with the site's
primary &quot;driver&quot;, <tt class="docutils literal"><span class="pre">slash.qpy</span></tt>, last discussed in <a class="reference external" href="/tags/python/2007-06-06-11-51.html">part five</a>.</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SiteDirectory</span><span class="p">(</span><span class="n">Directory</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">get_exports</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="s">&#39;Home&#39;</span><span class="p">,</span> <span class="s">&#39;The Home page of this site.&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;blog&#39;</span><span class="p">,</span> <span class="s">&#39;blog&#39;</span><span class="p">,</span> <span class="s">&#39;Weblog&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">index</span> <span class="p">[</span><span class="n">html</span><span class="p">]</span> <span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">title</span> <span class="o">=</span> <span class="n">get_site</span><span class="p">()</span><span class="o">.</span><span class="n">get_name</span><span class="p">()</span>
        <span class="n">header</span><span class="p">(</span><span class="n">title</span><span class="p">)</span>
        <span class="s">&#39;&lt;p&gt;&lt;strong&gt;It worked!&lt;/strong&gt;&lt;/p&gt;&#39;</span>
        <span class="s">&#39;&lt;p&gt;The &lt;strong&gt;</span><span class="si">%s</span><span class="s">&lt;/strong&gt; application lives at &lt;br /&gt;&lt;tt&gt;&#39;</span> <span class="o">%</span> <span class="n">title</span>
        <span class="n">get_site</span><span class="p">()</span><span class="o">.</span><span class="n">get_package_directory</span><span class="p">()</span>
        <span class="s">&#39;&lt;/tt&gt;&lt;/p&gt;&#39;</span>
        <span class="n">footer</span><span class="p">()</span>

    <span class="n">mw_journal</span> <span class="o">=</span> <span class="n">get_publisher</span><span class="p">()</span><span class="o">.</span><span class="n">get_root</span><span class="p">()[</span><span class="s">&#39;mw_journal&#39;</span><span class="p">]</span>
    <span class="n">blog</span> <span class="o">=</span> <span class="n">JournalDirectory</span><span class="p">(</span><span class="n">mw_journal</span><span class="p">)</span>
</pre></div>
<p>Or, we could wire up <tt class="docutils literal"><span class="pre">JournalDirectory</span></tt> as the 'root' of our application
like this:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SiteDirectory</span><span class="p">(</span><span class="n">JournalDirectory</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="c"># I&#39;ve implemented the JournalDatabase object and migrated some</span>
        <span class="c"># data into a Journal.</span>
        <span class="n">mw_journal</span> <span class="o">=</span> <span class="n">get_publisher</span><span class="p">()</span><span class="o">.</span><span class="n">get_root</span><span class="p">()[</span><span class="s">&#39;journals&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;mw&#39;</span><span class="p">)</span>
        <span class="n">JournalDirectory</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mw_journal</span><span class="p">)</span>
</pre></div>
<p>Going with the latter example, at this point we can restart the qp application
(<tt class="docutils literal"><span class="pre">qp</span> <span class="pre">blog</span> <span class="pre">restart</span></tt>) and visit <a class="reference external" href="http://localhost:8011/">http://localhost:8011/</a> and we should see a
list of available posts displayed which we can navigate to. Clearly we need to
do a bunch more work - implement a site look and feel; convert RST, Markdown,
and Textile formatted posts into HTML, implement RSS and Atom feeds, but the
basics of a journal or weblog application have come together. Fleshing out the
display of existing data will be our next step.</p>
<p>We still can't create, edit, or delete journal entries - we'll discuss that in
a soon to be forthcoming installment in this series.</p>
</div>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:477</guid>
  <pubDate>Wed, 20 Jun 2007 17:18:00 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
  <category>tutorial</category>
</item>
<item>
  <title>Python Web Application Diary, Part Six</title>
  <link>http://mikewatkins.ca/2007/06/08/python-web-application-diary-part-six/</link>
  <description><![CDATA[
<div class="document">
<p>In <a class="reference external" href="/tags/python/2007-06-06-11-51.html">part five</a> of this series we dove deep into <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> and looked at the
fundamentals of any QP application - <tt class="docutils literal"><span class="pre">SitePublisher</span></tt> and <tt class="docutils literal"><span class="pre">SiteDirectory</span></tt> -
as well as explored the use of <a class="reference external" href="http://www.mems-exchange.org/software/qpy/">QPY</a> templating. We also built a rudimentary UI
for our <tt class="docutils literal"><span class="pre">Entry</span></tt> object.</p>
<p>In this installment of our web application diary we'll work more with the
<a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> object database by injecting some data into it; exploring the
interactive interpreter (one of the cool features of Durus to be sure) and
starting the basis for a conversion script to take weblog data in <a class="reference external" href="http://pyblosxom.sourceforge.net/">PyBlosxom</a>
format and insert it into our <tt class="docutils literal"><span class="pre">blog</span></tt> application database.</p>
<div class="tip">
<p class="first admonition-title">Tip</p>
<p>Before going further, install <a class="reference external" href="http://codespeak.net/pyrepl/">Pyrepl</a> - this is required to support
QP / Durus interactive interpreter features, and adds significant
functionality (optional) to Python's own interactive interpreter.</p>
<p>To see <a class="reference external" href="http://codespeak.net/pyrepl/">Pyrepl</a> at work with regular Python launch:</p>
<pre class="last literal-block">
pythoni
</pre>
</div>
<div class="section" id="durus-the-database-you-already-know">
<h2>Durus, the database you already know</h2>
<p>Now I know what you are thinking. I think. Well, that is my theory and it is
mine and I own that theory. My theory is that you are thinking:</p>
<blockquote>
&quot;Object database? what sort of weird and strange alchemy is that? Fear
the unknown! Down with the unknown! Destroy the unknown with DELETE FROM
queries!&quot; -- you</blockquote>
<p>While object databases are not exactly in commonplace use by the IT industry,
within the <a class="reference external" href="http://python.org/">Python</a> community, there is a long history of kinship with object
databases with <a class="reference external" href="http://www.python.org/pypi/ZODB3">ZODB</a>, the Zope Object Database, arguably being the most well
known example.</p>
<p><a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> is patterned after ZODB, and indeed was written by developers who had
used ZODB extensively. Visit the <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> pages for more information on their
rationale for reinventing this particular wheel; from my own experience I can
only say that Durus is small and easy to read and understand.</p>
<p><strong>What exactly is an object database?</strong> Put simply, Durus and ZODB allow you
to persist your Python objects. Its more than <tt class="docutils literal"><span class="pre">pickle</span></tt> but not unlike pickle
in some respects.</p>
<div class="tip">
<p class="first admonition-title">Tip</p>
<p class="last">Launch a log viewer in another terminal window so you can watch
what happens as we make changes to the Durus database.
qp -l blog</p>
</div>
<div class="section" id="demonstrating-durus-interactively">
<h3>Demonstrating Durus, Interactively</h3>
<p>QP and Durus provide the facility to work directly with the Durus object
database directly. Lets fire up an interactive session to show Durus basics.</p>
<div class="highlight"><pre><span class="o">%</span> <span class="n">qp</span> <span class="o">-</span><span class="n">i</span> <span class="n">blog</span>
<span class="n">Profile</span><span class="p">,</span> <span class="n">connection</span><span class="p">,</span> <span class="n">publisher</span><span class="p">,</span> <span class="n">root</span><span class="p">,</span> <span class="n">sessions</span><span class="p">,</span> <span class="n">site</span><span class="p">,</span> <span class="n">users</span>
<span class="o">-&gt;&gt;</span>
</pre></div>
<p><strong>Working within the interactive session</strong>: <a class="reference external" href="http://codespeak.net/pyrepl/">Pyrepl</a> provides very useful
search and command history capabilities. Control-P and Control-N step through
previous lines entered. Control-R starts up reverse history search - start
typing an entry you've made previously (searches substrings within) and
Control-R again to step through the hits, if any.</p>
<p>Term expansion is perhaps my favorite <a class="reference external" href="http://codespeak.net/pyrepl/">Pyrepl</a> enhancement - it certainly is
the one that gets used enough. Try it now by entering in a couple letters:</p>
<pre class="literal-block">
-&gt;&gt; pu
</pre>
<p>And press <strong>Tab</strong> - you'll be rewarded with either <tt class="docutils literal"><span class="pre">publisher</span></tt> or a list of
terms in the namespace which match the letters entered so far. A <em>real</em>
timesaver.</p>
<p><strong>Access to objects</strong>: The interactive session provides us with access to QP
objects (connection, site, publisher), application objects (sessions, users),
a Profile testing class, but the most relevant to our discussion right now is
<tt class="docutils literal"><span class="pre">root</span></tt>.</p>
<p>By convention our application data lives under <tt class="docutils literal"><span class="pre">root</span></tt>, which is itself a
persistent object. Changes to <tt class="docutils literal"><span class="pre">root</span></tt> will persist from session to session
provided a call to <tt class="docutils literal"><span class="pre">connection.commit()</span></tt> has been made to commit the changes
to the database. Lets do some simple examples.</p>
<div class="highlight"><pre><span class="o">-&gt;&gt;</span> <span class="kn">from</span> <span class="nn">durus.persistent_dict</span> <span class="kn">import</span> <span class="n">PersistentDict</span>
<span class="o">-&gt;&gt;</span> <span class="n">mydict</span> <span class="o">=</span> <span class="n">PersistentDict</span><span class="p">()</span>
<span class="o">-&gt;&gt;</span> <span class="n">root</span><span class="p">[</span><span class="s">&#39;test&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">mydict</span>
<span class="o">-&gt;&gt;</span> <span class="n">connection</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="o">-&gt;&gt;</span>
<span class="o">%</span>
</pre></div>
<p>Control-D exits the interactive session, as it also exits a standard Python
interpreter. Restart the interpreter to see if our object was 'saved' or
persisted.</p>
<div class="highlight"><pre><span class="o">%</span> <span class="n">qp</span> <span class="o">-</span><span class="n">i</span> <span class="n">blog</span>
<span class="n">Profile</span><span class="p">,</span> <span class="n">connection</span><span class="p">,</span> <span class="n">publisher</span><span class="p">,</span> <span class="n">root</span><span class="p">,</span> <span class="n">sessions</span><span class="p">,</span> <span class="n">site</span><span class="p">,</span> <span class="n">test</span><span class="p">,</span> <span class="n">users</span>
<span class="o">-&gt;&gt;</span>
</pre></div>
<p>Very good, <tt class="docutils literal"><span class="pre">test</span></tt>, now shows up in our display -- objects living at the
<tt class="docutils literal"><span class="pre">root</span></tt> level are conveniently displayed as a reminder when we fire up an
interactive session. Lets put some data in test, but first, what was test?</p>
<div class="highlight"><pre><span class="o">-&gt;&gt;</span> <span class="n">test</span>
<span class="o">&lt;</span><span class="n">PersistentDict</span> <span class="mf">17020</span><span class="o">&gt;</span>
<span class="o">-&gt;&gt;</span> <span class="n">test</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
<span class="p">[]</span>
</pre></div>
<p>Right, now I remember. Ok, add some data.</p>
<div class="highlight"><pre><span class="o">-&gt;&gt;</span> <span class="n">test</span><span class="p">[</span><span class="mf">1</span><span class="p">]</span> <span class="o">=</span> <span class="s">&#39;My first persistent data&#39;</span>
<span class="o">-&gt;&gt;</span> <span class="n">connection</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
<span class="o">-&gt;&gt;</span>
</pre></div>
<p>Control-D to quit, and restart again to satisfy any fears that you may have
about your important data.</p>
<div class="highlight"><pre><span class="o">%</span> <span class="n">qp</span> <span class="o">-</span><span class="n">i</span> <span class="n">blog</span>
<span class="n">Profile</span><span class="p">,</span> <span class="n">connection</span><span class="p">,</span> <span class="n">journals</span><span class="p">,</span> <span class="n">publisher</span><span class="p">,</span> <span class="n">root</span><span class="p">,</span> <span class="n">sessions</span><span class="p">,</span> <span class="n">site</span><span class="p">,</span> <span class="n">test</span><span class="p">,</span> <span class="n">users</span>
<span class="o">-&gt;&gt;</span> <span class="n">test</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
<span class="p">[(</span><span class="mf">1</span><span class="p">,</span> <span class="s">&#39;My first persistent data&#39;</span><span class="p">)]</span>
<span class="o">-&gt;&gt;</span>
</pre></div>
<p>By now you can see that what we are doing is using Python to manage our data,
and, by virtue of subclassing one of <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> persistent object classes, we can
make our Python objects full partners in the Durus object database.</p>
<p>Durus is the database you already know. No object relational mappers to learn,
no SQL to learn or work around.</p>
</div>
</div>
<div class="section" id="durus-mini-faq">
<h2>Durus Mini FAQ</h2>
<dl class="docutils">
<dt>What about performance?</dt>
<dd>This is too difficult a question to answer simply, but its been my
experience that I  have been able to use Durus, instead of a SQL database
(Postgres is my personal favorite among the open source databases), far
more often than not. You won't put an on-line banking system processing
millions of transactions a day on to Durus or ZODB; but you might base on
Durus a complex company inventory system, even if there are hundreds of
thousands of items and related history. Third party solutions marry Durus
with relational databases as a back-end to Durus (transparent to the
application) to extend Durus (ZODB has similar approaches I'm told) even
further.</dd>
<dt>What about SQL / queries? How will I ever live?</dt>
<dd>One of the challenging things for a SQL-oriented developer (that was me,
some time ago) is to start thinking in pure-Python again. Its not hard,
but it does take some realignment of thought before it comes naturally -
at least for me. Being able to dispense with relational thinking in the
SQL sense brings a lot of design freedom.</dd>
<dt>What about sharing data with other systems?</dt>
<dd>My approach has been to export data as CSV or DIF for import into other
systems SQL databases, or to provide APIs such as XML-RPC or REST / JSON
approaches for other applications themselves, or to use RSS or Atom feeds
when it makes sense.</dd>
</dl>
<p><strong>The bottom line</strong>: Durus objects are Python objects. You've already invested
in learning and knowing Python, so you already know Durus, so there is no
time-to-learn downside to spending some time with Durus now. Lets press on.</p>
</div>
<div class="section" id="entries-with-no-home">
<h2>Entries with no home</h2>
<p>In <a class="reference external" href="/tags/python/2007-06-04-11-33.html">part three</a> of this series we turned a simple <tt class="docutils literal"><span class="pre">Entry</span></tt> object
into a full partner of a Durus database merely by subclassing
<tt class="docutils literal"><span class="pre">PersistentObject</span></tt> instead of the standard Python new-style class
<tt class="docutils literal"><span class="pre">object</span></tt>. In <a class="reference external" href="/tags/python/2007-06-04-14-18.html">part four</a> we kicked things up a notch by fleshing out our
<tt class="docutils literal"><span class="pre">Entry</span></tt> object with <em>specifications</em> provided by the <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> module
<tt class="docutils literal"><span class="pre">qp.lib.spec</span></tt>.</p>
<p>What we have not done, yet, is provide a place for our journal entries to
'live'. We need a container for <tt class="docutils literal"><span class="pre">Entry</span></tt>, and early on we decided to call
that container <tt class="docutils literal"><span class="pre">Journal</span></tt>. We are really going to kick things up a notch by
levering off of functionality provided by <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> in <tt class="docutils literal"><span class="pre">qp.lib.keep</span></tt>. A <tt class="docutils literal"><span class="pre">Keep</span></tt>
is a mapping of <tt class="docutils literal"><span class="pre">Keyed</span></tt> items using an integer as a key. Lets enhance
<tt class="docutils literal"><span class="pre">Entry</span></tt> first, then we'll write some unit tests for <tt class="docutils literal"><span class="pre">Journal</span></tt>, and then
write <tt class="docutils literal"><span class="pre">Journal</span></tt> itself.</p>
<p>All the code for the end-result objects will be available at the conclusion of
this series, but for you folks following along at home, lets dive in and
re-edit our <tt class="docutils literal"><span class="pre">journal.py</span></tt> and clean up our <tt class="docutils literal"><span class="pre">Entry</span></tt> object first. For
brevity's sake I have included imports relevant to both <tt class="docutils literal"><span class="pre">Entry</span></tt> and the
<tt class="docutils literal"><span class="pre">Journal</span></tt> object we will be writing.</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">dulcinea.base</span> <span class="kn">import</span> <span class="n">DulcineaPersistent</span>
<span class="kn">from</span> <span class="nn">dulcinea.sort</span> <span class="kn">import</span> <span class="n">attr_sort</span>
<span class="kn">from</span> <span class="nn">qp.lib.keep</span> <span class="kn">import</span> <span class="n">Keep</span><span class="p">,</span> <span class="n">Keyed</span><span class="p">,</span> <span class="n">Stamped</span>
<span class="kn">from</span> <span class="nn">qp.lib.spec</span> <span class="kn">import</span> <span class="n">add_getters_and_setters</span><span class="p">,</span> <span class="n">boolean</span><span class="p">,</span> <span class="n">both</span><span class="p">,</span> <span class="n">datetime_with_tz</span>
<span class="kn">from</span> <span class="nn">qp.lib.spec</span> <span class="kn">import</span> <span class="n">init</span><span class="p">,</span> <span class="n">pattern</span><span class="p">,</span> <span class="n">string</span><span class="p">,</span> <span class="n">spec</span>
<span class="kn">from</span> <span class="nn">qp.pub.user</span> <span class="kn">import</span> <span class="n">User</span>


<span class="k">class</span> <span class="nc">Entry</span><span class="p">(</span><span class="n">DulcineaPersistent</span><span class="p">,</span> <span class="n">Keyed</span><span class="p">,</span> <span class="n">Stamped</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    An entry in a journal.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">title_is</span> <span class="o">=</span> <span class="n">spec</span><span class="p">(</span>
        <span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="bp">None</span><span class="p">),</span>
        <span class="s">&quot;A string briefly describing the Entry&quot;</span><span class="p">)</span>
    <span class="n">text_is</span> <span class="o">=</span> <span class="n">spec</span><span class="p">(</span>
        <span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="bp">None</span><span class="p">),</span>
        <span class="s">&quot;The entry conten&quot;</span><span class="p">)</span>
    <span class="n">published_is</span> <span class="o">=</span> <span class="n">spec</span><span class="p">(</span>
        <span class="n">boolean</span><span class="p">,</span>
        <span class="s">&quot;Boolean indicating if Entry can be published&quot;</span><span class="p">)</span>
    <span class="n">author_is</span> <span class="o">=</span> <span class="n">spec</span><span class="p">(</span>
        <span class="n">User</span><span class="p">,</span>
        <span class="s">&quot;User responsible for creating entry&quot;</span><span class="p">)</span>
    <span class="n">created_is</span> <span class="o">=</span> <span class="n">datetime_with_tz</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="n">author</span><span class="p">):</span>
        <span class="n">Keyed</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
        <span class="n">Stamped</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
        <span class="n">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">author</span><span class="o">=</span><span class="n">author</span><span class="p">,</span> <span class="n">created</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">stamp</span><span class="p">,</span> <span class="n">published</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>

<span class="n">add_getters_and_setters</span><span class="p">(</span><span class="n">Entry</span><span class="p">)</span>
</pre></div>
<p>Lets now write <tt class="docutils literal"><span class="pre">Journal</span></tt> but before we write it, lets write the tests we
want it to pass, <strong>first</strong>, and then write the object. Typically you might
write only some of these tests, at least until you become familiar with the
various features of the <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> and <a class="reference external" href="http://www.mems-exchange.org/software/dulcinea/">Dulcinea</a> libraries. In our
<tt class="docutils literal"><span class="pre">./test/utest_journal.py</span></tt> we'll add another test.</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">parlez.journal</span> <span class="kn">import</span> <span class="n">Journal</span>

<span class="k">class</span> <span class="nc">JournalTest</span><span class="p">(</span><span class="n">UTest</span><span class="p">):</span>
    <span class="c"># we&#39;ll write this first, and then write Journal</span>

    <span class="k">def</span> <span class="nf">_pre</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="c"># set up a journal which we&#39;ll use for most tests.</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">j</span> <span class="o">=</span> <span class="n">Journal</span><span class="p">(</span><span class="s">&#39;science&#39;</span><span class="p">,</span> <span class="n">User</span><span class="p">(</span><span class="s">&#39;einstein&#39;</span><span class="p">))</span>
        <span class="c"># it is automatically taken down following each individual test</span>

    <span class="k">def</span> <span class="nf">init_test</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="c"># we want Journal to have a URL name and an owner, so force it</span>
        <span class="n">Journal</span><span class="p">(</span><span class="s">&#39;musings&#39;</span><span class="p">,</span> <span class="n">User</span><span class="p">(</span><span class="s">&#39;joe&#39;</span><span class="p">))</span>

    <span class="k">def</span> <span class="nf">create_entry_test</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">create_entry</span><span class="p">(),</span> <span class="n">Entry</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">add_test</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">e</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">create_entry</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
        <span class="k">assert</span> <span class="n">e</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">get_all_entries</span><span class="p">()</span>
        <span class="k">assert</span> <span class="n">e</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">get_entry</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">only_published_test</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="c"># nothing in</span>
        <span class="k">assert</span> <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">get_all_entries</span><span class="p">()</span> <span class="o">==</span> <span class="p">[]</span>
        <span class="n">e</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">create_entry</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
        <span class="n">e_published</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">create_entry</span><span class="p">()</span>
        <span class="n">e_published</span><span class="o">.</span><span class="n">set_published</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">e_published</span><span class="p">)</span>
        <span class="k">assert</span> <span class="n">e</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">get_entries</span><span class="p">()</span>
        <span class="k">assert</span> <span class="n">e_published</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">get_entries</span><span class="p">()</span>
        <span class="c"># publish e now</span>
        <span class="n">e</span><span class="o">.</span><span class="n">set_published</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
        <span class="k">assert</span> <span class="n">e</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">get_entries</span><span class="p">()</span>
        <span class="c"># both should be in reverse sorted result, e last</span>
        <span class="k">assert</span> <span class="p">[</span><span class="n">e_published</span><span class="p">,</span> <span class="n">e</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">j</span><span class="o">.</span><span class="n">get_recent_entries</span><span class="p">()</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="n">EntryTest</span><span class="p">()</span>
    <span class="n">JournalTest</span><span class="p">()</span>
</pre></div>
<p>I've kept this briefer than I'd like it to be, as there are some other tests
we need to write to completely cover our Journal object, but these tests
of primary functionality - add, retrieve, retrieve all and sort - should give
you the spirit of what we are trying to achieve here.</p>
</div>
<div class="section" id="pyblosxom-to-journal-conversion">
<h2>PyBlosxom to Journal Conversion</h2>
<p>A common challenge: you've got data in one system and need to move it into a
Durus database. A script to perform this task will be included in full at the
end of this series. For now lets sketch out what we need to do, and look at
how to access an application's <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> database from a script.</p>
<p>Pyblosxom maintains its files in a hierarchy that looks like something like
this:</p>
<pre class="literal-block">
../entries/categoryname/file1.txt
../entries/categoryname/someotherfile.rst
../entries/python/2007-06-08-08-44.rst
</pre>
<p>And so on. My particular installation uses a plugin which parses the entry
date from the file name if it is formatted as a datetime in the form of
yyyy-mm-dd-hh-mm.ext, so for files formatted like that I can set Entry.created
to a datetime parsed from the filename. Otherwise, I need to <tt class="docutils literal"><span class="pre">stat</span></tt> the file
and get its creation date from the operating system, which isn't always
reliable (in the case of edits and hapless administrators).</p>
<p>The file contents are simple for me to parse - content is either plain text,
or in my instance, mostly <a class="reference external" href="http://www.python.org/pypi/textile/">Textile</a> formatted with a sprinkling of <a class="reference external" href="http://docutils.sourceforge.net/rst.html">reST</a> and
<a class="reference external" href="http://www.freewisdom.org/projects/python-markdown/">Markdown</a>.:</p>
<pre class="literal-block">
Some article title
#author Mike Watkins
The article content.

.h2 A subtitle

More content. Etc.
</pre>
<p>I never used the #author directive; some files use the #parser directive to
indicate which formatter should be used; most rely on file extensions (.rst,
.txt, .mkd).</p>
<p>Ultimately my script needs to deliver to me:</p>
<ul class="simple">
<li>Entry date</li>
<li>Format</li>
<li>Title</li>
<li>Content</li>
</ul>
<p>And, if I intend to preserve the URLs (am debating this now... I really
dislike the existing bloxsom / Pyblosxom URL design) I'll need to carry that
information forward too. For now, lets assume we have a mapping containing
file paths as keys and a list with the four above noted data elements to work
with, and write a script to import that information into Durus.</p>
<div class="section" id="importing-data-to-durus">
<h3>Importing data to Durus</h3>
<p>Working with a QP application's Durus database is easy - remember, its just
Python.</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">qp.lib.site</span> <span class="kn">import</span> <span class="n">Site</span>
<span class="kn">from</span> <span class="nn">parlez.journal</span> <span class="kn">import</span> <span class="n">Entry</span><span class="p">,</span> <span class="n">Journal</span>

<span class="k">def</span> <span class="nf">bloxsom_to_mapping</span><span class="p">(</span><span class="n">entrypath</span><span class="p">):</span>
    <span class="c"># here you&#39;ll deal with the specifics - see a future article</span>
    <span class="n">data</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="c"># ...</span>
    <span class="k">return</span> <span class="n">data</span>

<span class="k">def</span> <span class="nf">add_journal_entries</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">journal</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">path</span><span class="p">,</span> <span class="n">entry_data</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
        <span class="c"># path I might store, or some component of it, in the Entry</span>
        <span class="c"># object to facilitate mapping old to new URLs in the future.</span>
        <span class="c"># for now, just ignoring it</span>
        <span class="n">created</span><span class="p">,</span> <span class="n">format</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">content</span> <span class="o">=</span> <span class="n">entry_data</span>
        <span class="n">entry</span> <span class="o">=</span> <span class="n">journal</span><span class="o">.</span><span class="n">create_entry</span><span class="p">()</span>
        <span class="n">entry</span><span class="o">.</span><span class="n">set_format</span><span class="p">(</span><span class="n">format</span><span class="p">)</span>
        <span class="n">entry</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="n">title</span><span class="p">)</span>
        <span class="n">entry</span><span class="o">.</span><span class="n">set_text</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
        <span class="c"># normally we don&#39;t bypass getters/setters</span>
        <span class="n">entry</span><span class="o">.</span><span class="n">created</span> <span class="o">=</span> <span class="n">created</span>
        <span class="n">entry</span><span class="o">.</span><span class="n">stamp</span> <span class="o">=</span> <span class="n">created</span>
        <span class="n">journal</span><span class="o">.</span><span class="n">add_entry</span><span class="p">(</span><span class="n">entry</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="n">BLOXSOM_ENTRY_PATH</span> <span class="o">=</span> <span class="s">&#39;/home/mw/bloxsom/entries&#39;</span>
    <span class="n">APP_NAME</span> <span class="o">=</span> <span class="s">&#39;blog&#39;</span>
    <span class="n">JOURNAL_NAME</span> <span class="o">=</span> <span class="s">&#39;mw&#39;</span>
    <span class="n">USER_ID</span> <span class="o">=</span> <span class="s">&#39;mw&#39;</span>

    <span class="c"># the Site object gives us the ability to access</span>
    <span class="c"># configuration information and live objects</span>
    <span class="n">site</span> <span class="o">=</span> <span class="n">Site</span><span class="p">(</span><span class="n">APP_NAME</span><span class="p">)</span>
    <span class="n">pub</span> <span class="o">=</span> <span class="n">site</span><span class="o">.</span><span class="n">get_publisher</span><span class="p">()</span>
    <span class="n">root</span> <span class="o">=</span> <span class="n">pub</span><span class="o">.</span><span class="n">get_root</span><span class="p">()</span>
    <span class="n">users</span> <span class="o">=</span> <span class="n">root</span><span class="p">[</span><span class="s">&#39;users&#39;</span><span class="p">]</span>
    <span class="c"># make sure I exist in Users</span>
    <span class="k">if</span> <span class="n">USER_ID</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">users</span><span class="p">:</span>
       <span class="n">user</span> <span class="o">=</span> <span class="n">pub</span><span class="o">.</span><span class="n">create_user</span><span class="p">(</span><span class="n">USER_ID</span><span class="p">)</span>
       <span class="n">users</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
    <span class="k">if</span> <span class="s">&#39;journal&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">root</span><span class="p">:</span>
        <span class="n">journal</span> <span class="o">=</span> <span class="n">Journal</span><span class="p">(</span><span class="n">JOURNAL_NAME</span><span class="p">,</span> <span class="n">user</span><span class="p">)</span>
        <span class="n">root</span><span class="p">[</span><span class="s">&#39;journal&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">journal</span>
    <span class="c"># move bloxsom data into Entry/Journal</span>
    <span class="n">add_journal_entries</span><span class="p">(</span><span class="n">bloxsom_to_mapping</span><span class="p">(</span><span class="n">BLOXSOM_ENTRY_PATH</span><span class="p">),</span>
                        <span class="n">journal</span><span class="p">)</span>
    <span class="c"># made it here, commit everything to the database</span>
    <span class="n">pub</span><span class="o">.</span><span class="n">get_connection</span><span class="p">()</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span>
    <span class="c"># that&#39;s it!</span>
</pre></div>
</div>
</div>
<div class="section" id="next-installment">
<h2>Next Installment</h2>
<p>When we return in part seven of this series we will further flesh out our UI
objects for <tt class="docutils literal"><span class="pre">Entry</span></tt> and <tt class="docutils literal"><span class="pre">Journal</span></tt>, adding methods for creating and editing
objects. At that point we'll have a basic journal or weblog application ready
to deploy to the world. Subsequent articles will add more functionality.</p>
</div>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:472</guid>
  <pubDate>Fri, 08 Jun 2007 15:44:00 GMT</pubDate>
  <category>durus</category>
  <category>python</category>
  <category>qp</category>
  <category>tutorial</category>
</item>
<item>
  <title>Python Web Application Diary, Part Five</title>
  <link>http://mikewatkins.ca/2007/06/06/python-web-application-diary-part-five/</link>
  <description><![CDATA[
<div class="document">
<p>In <a class="reference external" href="/tags/python/2007-06-04-14-18.html">part four</a> of this series we looked at the <tt class="docutils literal"><span class="pre">spec</span></tt> module from <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a>, and
created some basic <a class="reference external" href="http://www.mems-exchange.org/software/sancho/">Sancho</a> test cases. In this installment we'll write a few
lines of code for the web UI of the application, our first real exposure to
the web workings of QP.</p>
<div class="section" id="qp-applications">
<h2>QP Applications</h2>
<p>In <a class="reference external" href="/tags/python/2007-06-02-23-23.html">part two</a> we created file system hierarchies for both a library and our
project application. Since we plan on reusing our journal objects and related
UI, those components will live in our library and our application itself will
import them.</p>
<p>The fundamental requirements of any QP application are:</p>
<ol class="arabic simple">
<li>The application(s) must live somewhere in the QP search path. Issue <tt class="docutils literal"><span class="pre">qp</span>
<span class="pre">-h</span></tt> at the command line for details.</li>
<li>Applications must define a module called either <tt class="docutils literal"><span class="pre">slash.py</span></tt> or
<tt class="docutils literal"><span class="pre">slash.qpy</span></tt>. Both contain Python code, <tt class="docutils literal"><span class="pre">qpy</span></tt> files are QP
template-aware Python modules which we'll talk about more shortly.</li>
<li>The <tt class="docutils literal"><span class="pre">slash</span></tt> module must expose two objects, a <tt class="docutils literal"><span class="pre">SitePublisher</span></tt> which
defines the publishing environment and any application specific
customizations, as well as a <tt class="docutils literal"><span class="pre">SiteDirectory</span></tt> which defines the &quot;root&quot;
directory of the application.</li>
</ol>
<p>We generated a basic application skeleton using a tool cooked up just for this
article series, <a class="reference external" href="/software/files/qp/mkqpapp.py">mkqpapp.py</a>. This created in ~/qp_apps/blog the following
hierarchy:</p>
<pre class="literal-block">
CHANGES
README
__init__.py
bin/
doc/
slash.qpy
test/
ui/
    test/
var/
</pre>
<p>Ignoring the obvious or already discussed, lets explore files of
significance:</p>
<ol class="arabic">
<li><p class="first"><tt class="docutils literal"><span class="pre">slash.qpy</span></tt> as discussed earlier can be thought of as the <em>driver</em> or
root application directory of our new application.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">__init__.py</span></tt> defines the directory as a package; however should there be
any <tt class="docutils literal"><span class="pre">qpy</span></tt> modules in the given directory, __init__.py must include two
lines of code:</p>
<pre class="literal-block">
from qpy.compile import compile_qpy_files
compile_qpy_files(__path__[0])
</pre>
<p><a class="reference external" href="http://www.mems-exchange.org/software/qpy/">QPY</a>, which was installed in <a class="reference external" href="/tags/python/2007-05-31-10-49.html">part one</a> of this series, provides unicode and
quote-safe Python <em>templating</em>, in a manner quite different than all other
Python templating approaches. Diligent use of <tt class="docutils literal"><span class="pre">qpy</span></tt> can reduce or eliminate
your application's risk of being exploited by <em>cross site scripting</em> attacks,
and SQL injection attacks, if your application uses SQL.</p>
<p>No magic or import hooks are required to integrate QPY with regular Python
code; the two lines in <tt class="docutils literal"><span class="pre">__init__.py</span></tt> ensure that QPY files are compiled as
regular Python code. Its a small price to pay for much flexibility as we'll
see soon.</p>
</li>
</ol>
</div>
<div class="section" id="exposing-objects-methods-or-functions-on-the-web">
<h2>Exposing Objects, Methods or Functions on the Web</h2>
<p>Lets now open the template <tt class="docutils literal"><span class="pre">slash.qpy</span></tt> module, explore, and make some
changes. If you've not already started the template application created in
<a class="reference external" href="/tags/python/2007-06-02-23-23.html">part two</a>, launch it now:</p>
<pre class="literal-block">
qp blog start
</pre>
<p>Visit the application at <a class="reference external" href="http://localhost:8011/">http://localhost:8011/</a> and you'll see:</p>
<blockquote>
<p><strong>It worked!</strong></p>
<p>The <strong>blog</strong> application lives at <tt class="docutils literal"><span class="pre">/usr/home/yourhomedir/qp_sites/blog</span></tt>.</p>
</blockquote>
<p>Lets edit <tt class="docutils literal"><span class="pre">slash.qpy</span></tt> and make some changes. First of all, since we've not
discussed <tt class="docutils literal"><span class="pre">https</span></tt> secure http communications at all, yet, lets comment out
some of the configuration:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SitePublisher</span> <span class="p">(</span><span class="n">DurusPublisher</span><span class="p">):</span>

    <span class="n">configuration</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
        <span class="n">durus_address</span><span class="o">=</span><span class="p">(</span><span class="s">&#39;localhost&#39;</span><span class="p">,</span> <span class="mf">7011</span><span class="p">),</span>
        <span class="n">http_address</span><span class="o">=</span><span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="mf">8011</span><span class="p">),</span>
        <span class="c"># as_https_address=(&#39;localhost&#39;, 9011),</span>
        <span class="c"># https_address=(&#39;&#39;, 10011),</span>
        <span class="p">)</span>
</pre></div>
<p>The <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> README contains a recipe for using <tt class="docutils literal"><span class="pre">stunnel</span></tt> for providing <tt class="docutils literal"><span class="pre">https</span></tt>
SSL abilities to your QP applications.</p>
<div class="section" id="sitedirectory-our-master-controller">
<h3>SiteDirectory, Our Master Controller</h3>
<p>Lets have a look at <tt class="docutils literal"><span class="pre">SiteDirectory</span></tt>, a required class which defines in
essence the root of our web application. All paths lead from here, as we'll
see now.</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SiteDirectory</span><span class="p">(</span><span class="n">Directory</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">get_exports</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="s">&#39;Home&#39;</span><span class="p">,</span> <span class="s">&#39;The Home page of this site.&#39;</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">index</span> <span class="p">[</span><span class="n">html</span><span class="p">]</span> <span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">title</span> <span class="o">=</span> <span class="n">get_site</span><span class="p">()</span><span class="o">.</span><span class="n">get_name</span><span class="p">()</span>
        <span class="n">header</span><span class="p">(</span><span class="n">title</span><span class="p">)</span>
        <span class="s">&#39;&lt;p&gt;&lt;strong&gt;It worked!&lt;/strong&gt;&lt;/p&gt;&#39;</span>
        <span class="s">&#39;&lt;p&gt;The &lt;strong&gt;</span><span class="si">%s</span><span class="s">&lt;/strong&gt; application lives at &lt;br /&gt;&lt;tt&gt;&#39;</span> <span class="o">%</span> <span class="n">title</span>
        <span class="n">get_site</span><span class="p">()</span><span class="o">.</span><span class="n">get_package_directory</span><span class="p">()</span>
        <span class="s">&#39;&lt;/tt&gt;&lt;/p&gt;&#39;</span>
        <span class="n">footer</span><span class="p">()</span>
</pre></div>
<p>Two items of note:</p>
<p><tt class="docutils literal"><span class="pre">get_exports()</span></tt> explicitly defines what methods or functions we are willing
to expose to the World Wide Web (or to other applications via REST or other
RPC methods). Nothing is shared with the world by default, everything is
explicitly enabled, if at all.</p>
<p><tt class="docutils literal"><span class="pre">get_exports()</span></tt> returns a four element tuple containing:</p>
<blockquote>
<ol class="arabic simple">
<li>The current directory 'pathname' to be exposed to the web, a null string
if the path is to be '/'.</li>
<li>The name of the Python callable that the pathname refers to. The
publisher 'translates' pathnames into callables, making it easy to expose
deeply nested hierarchies of functionality.</li>
<li>A short name describing the callable; this is optionally used for menus.</li>
<li>A longer descriptive phrase describing the callable; this is optionally
used for anchor titles / tooltips.</li>
</ol>
</blockquote>
<p>Thus <tt class="docutils literal"><span class="pre">get_exports</span></tt> currently defines only a single exposed callable, a null
path component (''), which translates to the <tt class="docutils literal"><span class="pre">index</span></tt> of the class.</p>
<p>The <tt class="docutils literal"><span class="pre">SiteDirectory</span></tt> method <tt class="docutils literal"><span class="pre">def</span> <span class="pre">index</span> <span class="pre">[html]</span> <span class="pre">(self):</span></tt> introduces another
significant component of the <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> web application framework and family, <a class="reference external" href="http://www.mems-exchange.org/software/qpy/">QPY</a>,
which provides almost fully transparent  source-code transformation of an
&quot;html template&quot; into pure Python. QPY delivers other capabilities which
deserve some looking at now.</p>
</div>
<div class="section" id="html-template-basics-hello-world">
<h3>HTML Template Basics - Hello, World</h3>
<p>Lets add a new method to our <tt class="docutils literal"><span class="pre">SiteDirectory</span></tt> class and expose it to the
web. First the method:</p>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">hello</span> <span class="p">[</span><span class="n">html</span><span class="p">]</span> <span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="s">&#39;&lt;p&gt;Hello, world&lt;/p&gt;&#39;</span>
</pre></div>
<p>If you restart your application, and visit: <a class="reference external" href="http://localhost:8011/hello">http://localhost:8011/hello</a>:</p>
<pre class="literal-block">
qp blog restart
</pre>
<p>You'll be rewarded with the default <cite>404</cite> response (which we can easily
replace). Why? Because we forgot to expose <tt class="docutils literal"><span class="pre">hello()</span></tt> to the web:</p>
<blockquote>
'hello'?</blockquote>
<p>Don't believe that was a <tt class="docutils literal"><span class="pre">404</span></tt> response? Lets also run the QP log watcher in
another terminal window:</p>
<pre class="literal-block">
qp -l blog
</pre>
<p>You'll discover your last log entry looks something like:</p>
<pre class="literal-block">
2007-06-06 19:45:04 404 .007931 127.0.0.1 - - 3005 http GET /hello - Mozilla/5.0_
</pre>
<p>By now you know what must be done. Yes, that's right, we need to add an entry
to <tt class="docutils literal"><span class="pre">get_exports()</span></tt>:</p>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">get_exports</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="s">&#39;Home&#39;</span><span class="p">,</span> <span class="s">&#39;The Home page of this site.&#39;</span><span class="p">)</span>
    <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;hello&#39;</span><span class="p">,</span> <span class="s">&#39;hello&#39;</span><span class="p">,</span> <span class="s">&#39;Greetings&#39;</span><span class="p">,</span> <span class="s">&#39;A page for salutations&#39;</span><span class="p">)</span>
</pre></div>
<p>Restart the application -- I map a key in <tt class="docutils literal"><span class="pre">vim</span></tt> to restart the current project
I am editing -- and the revisit <a class="reference external" href="http://localhost:8011/hello">http://localhost:8011/hello</a> and you'll now
see returned:</p>
<blockquote>
Hello, world</blockquote>
<p>That's not very exciting I admit. Lets alter hello() and supply the new method
with some user-provided input to our hello method. For the purposes of this
example, in order to keep things simple at this stage, lets pretend <tt class="docutils literal"><span class="pre">hello</span></tt>
is asked to process the results of a form submission. We'll define, outside of our
hello() method, a dictionary called form as such:</p>
<div class="highlight"><pre><span class="n">form</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
    <span class="n">title</span><span class="o">=</span><span class="s">&#39;User supplied title&#39;</span><span class="p">,</span>
    <span class="n">text</span><span class="o">=</span><span class="s">&#39;Malicious user supplied &lt;script&gt;destroy_you_all()&lt;/script&gt;&#39;</span><span class="p">)</span>
</pre></div>
<p>Lets update <tt class="docutils literal"><span class="pre">hello</span></tt>:</p>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">hello</span> <span class="p">[</span><span class="n">html</span><span class="p">]</span> <span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="s">&#39;&lt;p&gt;Hello, world, I&#39;</span><span class="n">m</span> <span class="n">a</span> <span class="n">malicious</span> <span class="n">user</span> <span class="ow">and</span> <span class="n">posted</span> <span class="n">this</span><span class="p">:</span><span class="o">&lt;/</span><span class="n">p</span><span class="o">&gt;</span><span class="s">&#39;</span>
    <span class="s">&#39;&lt;h2&gt;</span><span class="si">%(title)s</span><span class="s">&lt;/h2&gt;&#39;</span> <span class="o">%</span> <span class="n">form</span>
    <span class="s">&#39;&lt;p&gt;</span><span class="si">%(text)s</span><span class="s">&lt;/p&gt;&#39;</span> <span class="o">%</span> <span class="n">form</span>
</pre></div>
<p>The result:</p>
<pre class="literal-block">
Hello, world, I am a malicious user and posted this:

User supplied title

Malicious user supplied &lt;script&gt;destroy_you_all()&lt;/script&gt;
</pre>
<p>View source and you'll see that the content has been fully escaped and quoted:</p>
<blockquote>
[snip]
Malicious user supplied &amp;lt;script&amp;gt;destroy_you_all()&amp;lt;/script&amp;gt;</blockquote>
<p>This demonstrates one of the core features of QPY - safe quoting of content
not explicitly declared as safe beforehand.</p>
<p>With this lesson in mind, its time now to write a basic shell of a user
interface for our Entry and Journal objects. The interface code won't go
directly into our application but into our library of useful reusable routines
- but of course you could simply create the objects and related UI in the
<tt class="docutils literal"><span class="pre">blog</span></tt> application hierarchy.</p>
</div>
</div>
<div class="section" id="entry-ui">
<h2>Entry UI</h2>
<p>Our last task for this installment is to flesh out the basic UI for the
<tt class="docutils literal"><span class="pre">Entry</span></tt> object:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">qp.fill.directory</span> <span class="kn">import</span> <span class="n">Directory</span>
<span class="kn">from</span> <span class="nn">qp.lib.spec</span> <span class="kn">import</span> <span class="n">require</span>
<span class="kn">from</span> <span class="nn">qp.pub.common</span> <span class="kn">import</span> <span class="n">header</span><span class="p">,</span> <span class="n">footer</span>
<span class="kn">from</span> <span class="nn">parlez.journal</span> <span class="kn">import</span> <span class="n">Entry</span><span class="p">,</span> <span class="n">Journal</span><span class="p">,</span> <span class="n">JournalDatabase</span>

<span class="c"># this is for demonstration only.</span>
<span class="kn">from</span> <span class="nn">qp.pub.user</span> <span class="kn">import</span> <span class="n">User</span>
<span class="n">test_entry</span> <span class="o">=</span> <span class="n">Entry</span><span class="p">(</span><span class="n">User</span><span class="p">(</span><span class="s">&#39;foo&#39;</span><span class="p">))</span>
<span class="n">test_entry</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">&#39;An example journal entry&#39;</span><span class="p">)</span>
<span class="n">test_entry</span><span class="o">.</span><span class="n">set_text</span><span class="p">(</span><span class="s">&quot;To QPY, or not to QPY, &lt;that&gt; is the question &amp; what&#39;s for dinner?&quot;</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">EntryUI</span><span class="p">(</span><span class="n">Directory</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    This class provides the functionality to display a single entry,</span>
<span class="sd">    edit a new or existing entry, delete an entry, and to represent</span>
<span class="sd">    an entry in different ways including RSS or Atom.</span>

<span class="sd">    Our application urls for this UI component will be:</span>

<span class="sd">        ../1234/</span>
<span class="sd">        ../1234/edit</span>
<span class="sd">        ../1234/delete</span>
<span class="sd">        ../1234/index.rss</span>
<span class="sd">        ../1234/index.xml</span>
<span class="sd">    &quot;&quot;&quot;</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="n">component</span><span class="o">=</span><span class="n">test_entry</span><span class="p">):</span>
        <span class="n">require</span><span class="p">(</span><span class="n">component</span><span class="p">,</span> <span class="n">Entry</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">entry</span> <span class="o">=</span> <span class="n">component</span>

    <span class="k">def</span> <span class="nf">get_exports</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;edit&#39;</span><span class="p">,</span> <span class="s">&#39;edit&#39;</span><span class="p">,</span> <span class="s">&#39;Edit Entry&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;delete&#39;</span><span class="p">,</span> <span class="s">&#39;delete&#39;</span><span class="p">,</span> <span class="s">&#39;Delete Entry&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;index.rss&#39;</span><span class="p">,</span> <span class="s">&#39;rss&#39;</span><span class="p">,</span> <span class="s">&#39;RSS&#39;</span><span class="p">,</span> <span class="s">&#39;RSS feed for this entry&#39;</span><span class="p">)</span>
        <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;index.xml&#39;</span><span class="p">,</span> <span class="s">&#39;atom&#39;</span><span class="p">,</span> <span class="s">&#39;Atom&#39;</span><span class="p">,</span> <span class="s">&#39;Atom feed for this entry&#39;</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">index</span> <span class="p">[</span><span class="n">html</span><span class="p">]</span> <span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="c"># python docstrings can&#39;t be included in [html] templates</span>
        <span class="c"># this template could also deliver the output of other</span>
        <span class="c"># template engines such as Genshi, Cheetah, Mako, etc.</span>
        <span class="c"># lets stick with QPY for now.</span>
        <span class="n">title</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">entry</span><span class="o">.</span><span class="n">get_title</span><span class="p">()</span>
        <span class="n">header</span><span class="p">(</span><span class="n">title</span><span class="p">)</span>
        <span class="s">&#39;&lt;h1&gt;</span><span class="si">%s</span><span class="s">&lt;/h1&gt;&#39;</span> <span class="o">%</span> <span class="n">title</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">entry</span><span class="o">.</span><span class="n">get_text</span><span class="p">()</span>
        <span class="n">footer</span><span class="p">(</span><span class="n">title</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">atom</span> <span class="p">[</span><span class="n">html</span><span class="p">]</span> <span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s">&#39;Not Implemented&#39;</span>

    <span class="c"># lets just point all these methods to atom / not implemented for now until</span>
    <span class="c"># we implement each</span>
    <span class="n">edit</span> <span class="o">=</span> <span class="n">delete</span> <span class="o">=</span> <span class="n">rss</span> <span class="o">=</span> <span class="n">atom</span>
</pre></div>
<p>If you want to race ahead and see what this looks like from the browser side,
update <tt class="docutils literal"><span class="pre">slash.qpy</span></tt> by adding an import, changing <tt class="docutils literal"><span class="pre">get_exports</span></tt> and <tt class="docutils literal"><span class="pre">SiteDirectory</span></tt> as
follows (don't forget to restart the application afterwards):</p>
<div class="highlight"><pre><span class="c"># import your UI object from wherever you put it.</span>
<span class="kn">from</span> <span class="nn">parlez.ui.journal</span> <span class="kn">import</span> <span class="n">EntryUI</span>
</pre></div>
<p>Modify <tt class="docutils literal"><span class="pre">get_exports</span></tt> as such:</p>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">get_exports</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span><span class="p">,</span> <span class="s">&#39;Home&#39;</span><span class="p">,</span> <span class="s">&#39;The Home page of this site.&#39;</span><span class="p">)</span>
    <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;hello&#39;</span><span class="p">,</span> <span class="s">&#39;hello&#39;</span><span class="p">,</span> <span class="s">&#39;Greetings&#39;</span><span class="p">,</span> <span class="s">&#39;A page for salutations&#39;</span><span class="p">)</span>
    <span class="k">yield</span> <span class="p">(</span><span class="s">&#39;test_entry&#39;</span><span class="p">,</span> <span class="s">&#39;test_entry&#39;</span><span class="p">,</span> <span class="s">&#39;EntryUI Test&#39;</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
</pre></div>
<p>Modify <tt class="docutils literal"><span class="pre">SiteDirectory</span></tt> by adding an attribute which points to an instance of
EntryUI:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">SiteDirectory</span><span class="p">(</span><span class="n">Directory</span><span class="p">):</span>
    <span class="c"># snip</span>

    <span class="n">test_entry</span> <span class="o">=</span> <span class="n">EntryUI</span><span class="p">()</span>
</pre></div>
<p>And then restart the app (<tt class="docutils literal"><span class="pre">qp</span> <span class="pre">blog</span> <span class="pre">restart</span></tt>) and visit the following URL's:</p>
<blockquote>
<ul class="simple">
<li><a class="reference external" href="http://localhost:8011/test_entry">http://localhost:8011/test_entry</a> (note what happens)</li>
<li><a class="reference external" href="http://localhost:8011/test_entry/">http://localhost:8011/test_entry/</a></li>
<li><a class="reference external" href="http://localhost:8011/test_entry/edit">http://localhost:8011/test_entry/edit</a></li>
<li><a class="reference external" href="http://localhost:8011/test_entry/delete">http://localhost:8011/test_entry/delete</a></li>
<li><a class="reference external" href="http://localhost:8011/test_entry/index.rss">http://localhost:8011/test_entry/index.rss</a></li>
<li><a class="reference external" href="http://localhost:8011/test_entry/index.xml">http://localhost:8011/test_entry/index.xml</a></li>
</ul>
</blockquote>
</div>
<div class="section" id="next-installment">
<h2>Next Installment</h2>
<p>When we return in part six of this series we will inject some real <tt class="docutils literal"><span class="pre">Entry</span></tt>
data into our <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> database and explore how we will work with Durus objects
interactively, from our application, and from scripts.</p>
<p>After that we'll turn our application shell into a functioning application by
stripping out the quick and dirty demonstration data hacks and completing our
&quot;controller&quot; logic for EntryUI and Journal user interface classes.</p>
</div>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:471</guid>
  <pubDate>Wed, 06 Jun 2007 18:51:00 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
  <category>tutorial</category>
</item>
<item>
  <title>Python Web Application Diary, Part Four</title>
  <link>http://mikewatkins.ca/2007/06/04/python-web-application-diary-part-four/</link>
  <description><![CDATA[
<div class="document">
<p>In <a class="reference external" href="/tags/python/2007-06-04-11-33.html">part three</a> of this series we determined that <tt class="docutils literal"><span class="pre">Entry</span></tt> and <tt class="docutils literal"><span class="pre">Journal</span></tt>
classes will be required, and we started to look at how straight Python
classes could become full database participants in a <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> object database.</p>
<p>Our object model so far is very simplistic; lets add a healthy dose of
constraints to aid both in testing and also prevent unintended (mis)use down
the road.</p>
<p>I promise we'll get to <em>webby</em> things soon enough, we are just waiting for the
chorus to come around again on the guitar. (All apologies to Arlo Guthrie)</p>
<div class="section" id="specifications-contracts-for-busy-developers">
<h2>Specifications: Contracts for Busy Developers</h2>
<p>The <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> package has a wonderful module, <tt class="docutils literal"><span class="pre">qp.lib.spec</span></tt> which deserves to get
more attention whether QP does or not.</p>
<p><tt class="docutils literal"><span class="pre">spec</span></tt> provides an easy way to declare or <em>specify</em> what various object
attributes should contain, without littering your code with miles of asserts
and other test. Examples will make things clear - lets take our too-simple
<tt class="docutils literal"><span class="pre">Entry</span></tt> object and beef it up.  First the original database-aware object:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">durus.persistent</span> <span class="kn">import</span> <span class="n">PersistentObject</span>

<span class="k">class</span> <span class="nc">Entry</span><span class="p">(</span><span class="n">PersistentObject</span><span class="p">):</span>
    <span class="n">title</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="n">text</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="n">author</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="n">created</span> <span class="o">=</span> <span class="bp">None</span>
</pre></div>
<p><strong>Out of control</strong>: Clearly the object as its described presents a problem -
its just an empty 'bag' with no constraints on what a user/developer might
attempt to do with it. For example, whether intended or not, our dumb object
allows for all sorts of questionable attribute assignments, as shown in this
interactive session:</p>
<div class="highlight"><pre><span class="o">-&gt;&gt;</span> <span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="p">()</span>
<span class="o">-&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">title</span> <span class="o">=</span> <span class="s">&#39;my title&#39;</span>  <span class="c"># so far so good</span>
<span class="o">-&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">title</span> <span class="o">=</span> <span class="bp">None</span>        <span class="c"># probably reasonable</span>
<span class="o">-&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">title</span> <span class="o">=</span> <span class="mf">123.456</span>     <span class="c"># not at all what we want</span>
<span class="o">-&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">created</span> <span class="o">=</span> <span class="mf">3.1415</span>
<span class="o">-&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">some_new_attribute</span> <span class="o">=</span> <span class="s">&quot;foo&quot;</span>
</pre></div>
<p>The dynamic nature of Python is both blessing and curse at times; the above
object requires lots of additional code to ensure that data it manages is what
the developer intended, leading to significant code expansion via tests and
assertions, reducing readability along the way.</p>
<p><strong>In control</strong>: There is another way.  Lets use <tt class="docutils literal"><span class="pre">spec</span></tt> and apply
specifications and some helper methods:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">durus.persistent</span> <span class="kn">import</span> <span class="n">PersistentObject</span>
<span class="kn">from</span> <span class="nn">qp.lib.spec</span> <span class="kn">import</span> <span class="n">datetime_with_tz</span><span class="p">,</span> <span class="n">spec</span><span class="p">,</span> <span class="n">string</span>
<span class="kn">from</span> <span class="nn">qp.lib.spec</span> <span class="kn">import</span> <span class="n">add_getters_and_setters</span>

<span class="k">class</span> <span class="nc">Entry</span><span class="p">(</span><span class="n">PersistentObject</span><span class="p">):</span>

    <span class="n">title_is</span> <span class="o">=</span> <span class="n">spec</span><span class="p">(</span>
        <span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="bp">None</span><span class="p">),</span>
        <span class="s">&#39;A short description of the entry&#39;</span><span class="p">)</span>
    <span class="n">text_is</span> <span class="o">=</span> <span class="n">spec</span><span class="p">(</span>
        <span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="bp">None</span><span class="p">),</span>
        <span class="s">&#39;The full text of the entry&#39;</span><span class="p">)</span>
    <span class="n">author_is</span> <span class="o">=</span> <span class="n">spec</span><span class="p">(</span>
        <span class="n">User</span><span class="p">,</span>
        <span class="s">&#39;The individual responsible for the content of the entry&#39;</span><span class="p">)</span>
    <span class="n">created_is</span> <span class="o">=</span> <span class="n">datetime_with_tz</span>

<span class="n">add_getters_and_setters</span><span class="p">(</span><span class="n">Entry</span><span class="p">)</span>
</pre></div>
<p>A spec can be a simple type assignment (see <tt class="docutils literal"><span class="pre">created_is</span></tt> above) or make use
of the spec function which allows for a certain amount of self-documentation
which can be very helpful. Arguments supplied in tuple imply the specification
<tt class="docutils literal"><span class="pre">either</span></tt>, or you can spell it out: <tt class="docutils literal"><span class="pre">either(string,</span> <span class="pre">None)</span></tt>.</p>
<p>Now lets run through the same interactive session as before:</p>
<div class="highlight"><pre><span class="o">-&gt;&gt;</span> <span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="p">()</span>
<span class="o">-&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="s">&#39;my title&#39;</span><span class="p">)</span>
<span class="o">-&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="bp">None</span><span class="p">)</span>
<span class="o">-&gt;&gt;</span> <span class="n">e</span><span class="o">.</span><span class="n">set_title</span><span class="p">(</span><span class="mf">123.456</span><span class="p">)</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
  <span class="n">File</span> <span class="s">&quot;&lt;input&gt;&quot;</span><span class="p">,</span> <span class="n">line</span> <span class="mf">2</span><span class="p">,</span> <span class="ow">in</span> <span class="o">&lt;</span><span class="n">module</span><span class="o">&gt;</span>
  <span class="n">File</span> <span class="s">&quot;/usr/local/lib/python2.5/site-packages/qp/lib/spec.py&quot;</span><span class="p">,</span> <span class="n">line</span> <span class="mf">725</span><span class="p">,</span> <span class="ow">in</span> <span class="n">f</span>
    <span class="n">require</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">klass</span><span class="p">,</span> <span class="n">name</span> <span class="o">+</span> <span class="s">&#39;_is&#39;</span><span class="p">))</span>
  <span class="n">File</span> <span class="s">&quot;/usr/local/lib/python2.5/site-packages/qp/lib/spec.py&quot;</span><span class="p">,</span> <span class="n">line</span> <span class="mf">171</span><span class="p">,</span> <span class="ow">in</span> <span class="n">require</span>
    <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="n">error</span><span class="p">)</span>
<span class="ne">TypeError</span><span class="p">:</span>
  <span class="n">Expected</span><span class="p">:</span> <span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
  <span class="n">A</span> <span class="n">short</span> <span class="n">description</span> <span class="n">of</span> <span class="n">the</span> <span class="n">entry</span>
  <span class="n">Got</span><span class="p">:</span> <span class="mf">123.456</span>
</pre></div>
<p>Aha, for the cost of a pair of get and set methods (no moaning please, we
didn't even have to write the getter and setter ourselves and they don't
clutter the code), we've effectively constrained what type of data can be
assigned to the <tt class="docutils literal"><span class="pre">title</span></tt> attribute of Entry, while also preserving the easy
to read nature of the original, simple, code.</p>
<p>To demonstrate the utility of <tt class="docutils literal"><span class="pre">spec</span></tt>, I've pulled a number of examples from
<a class="reference external" href="http://www.mems-exchange.org/software/dulcinea/">Dulcinea</a> and my own code. As you can see, there is great flexibility provided:</p>
<div class="highlight"><pre><span class="n">date_is</span> <span class="o">=</span> <span class="n">datetime</span>

<span class="n">approvals_is</span> <span class="o">=</span> <span class="n">spec</span><span class="p">(</span>
    <span class="n">sequence</span><span class="p">(</span><span class="n">DulcineaUser</span><span class="p">,</span> <span class="n">set</span><span class="p">),</span>
    <span class="s">&quot;The users who agree the issue is resolved.&quot;</span><span class="p">)</span>

<span class="n">issues_is</span> <span class="o">=</span> <span class="n">spec</span><span class="p">(</span>
    <span class="n">mapping</span><span class="p">({</span><span class="n">string</span><span class="p">:</span><span class="n">Issue</span><span class="p">},</span> <span class="n">PersistentDict</span><span class="p">),</span>
    <span class="s">&quot;Mapping of issue IDs to issues.&quot;</span><span class="p">)</span>

<span class="n">id_is</span> <span class="o">=</span> <span class="n">spec</span><span class="p">(</span>
    <span class="n">pattern</span><span class="p">(</span><span class="s">&#39;^[-A-Za-z0-9_@.]*$&#39;</span><span class="p">),</span>
    <span class="s">&quot;unique among users here&quot;</span><span class="p">)</span>

<span class="c"># some specs are referred to over and over again</span>

<span class="n">datetime_without_tz</span> <span class="o">=</span> <span class="n">both</span><span class="p">(</span><span class="n">datetime</span><span class="p">,</span> <span class="n">with_attribute</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="bp">None</span><span class="p">))</span>
<span class="n">datetime_with_tz</span> <span class="o">=</span> <span class="n">both</span><span class="p">(</span><span class="n">datetime</span><span class="p">,</span> <span class="n">with_attribute</span><span class="p">(</span><span class="n">tzinfo</span><span class="o">=</span><span class="n">no</span><span class="p">(</span><span class="bp">None</span><span class="p">)))</span>
<span class="n">email_pattern</span> <span class="o">=</span> <span class="n">pattern</span><span class="p">(</span><span class="s">&quot;^.+@.+\..{2,4}$&quot;</span><span class="p">)</span>
<span class="n">existing_user</span> <span class="o">=</span> <span class="n">both</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">with_attribute</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="n">no</span><span class="p">(</span><span class="bp">None</span><span class="p">)))</span>
<span class="n">hex_pattern</span> <span class="o">=</span> <span class="n">pattern</span><span class="p">(</span><span class="s">&#39;[a-fA-F0-9]*$&#39;</span><span class="p">)</span>

<span class="c"># reuse them</span>

<span class="n">email_is</span> <span class="o">=</span> <span class="n">email_pattern</span>
<span class="n">id_is</span> <span class="o">=</span> <span class="n">spec</span><span class="p">(</span>
    <span class="n">hex_pattern</span><span class="p">,</span>
    <span class="s">&#39;a lower case alphanumeric pattern&#39;</span><span class="p">)</span>

<span class="c"># use the specifications in tests (more powerful and cleaner than</span>
<span class="c"># testing for type and instance alone)</span>

<span class="n">require</span><span class="p">(</span><span class="n">thing</span><span class="p">,</span> <span class="n">either</span><span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">))</span>
<span class="n">match</span><span class="p">(</span><span class="n">a_user</span><span class="p">,</span> <span class="n">existing_user</span><span class="p">)</span> <span class="c"># returns boolean</span>
</pre></div>
<p>My experience is that you can create fairly complex specifications that remain
very readable. Have a complex object that has to be &quot;just so&quot; before it is
committed to a database in a transaction? Specify everything, and check it for
sanity with a one line assertion: <tt class="docutils literal"><span class="pre">assert</span>
<span class="pre">get_spec_problems(theobject_instance)</span> <span class="pre">==</span> <span class="pre">[]</span></tt> and you are done.</p>
</div>
<div class="section" id="testing-testing-one-two-three">
<h2>Testing, Testing, One Two Three</h2>
<p>As you might imagine, it becomes easier to write unit tests when our objects
are so highly specified. <a class="reference external" href="http://www.mems-exchange.org/software/sancho/">Sancho</a>, a unit testing framework also from the same
development shop from which <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> originates, is designed for projects and teams
who prefer to leave code in a working state, all or most of the time.</p>
<p>Tests live in ./test, one level down from our objects being tested, and there
is no <tt class="docutils literal"><span class="pre">__init__.py</span></tt>. A utility, urun.py, will execute one test supplied on
the command line, or all tests in the <tt class="docutils literal"><span class="pre">test</span></tt> subdirectories in the current
directory and below. Lets write one for <tt class="docutils literal"><span class="pre">Entry</span></tt>:</p>
<div class="highlight"><pre><span class="c"># /www/lib/parlez/test/utest_journal.py</span>
<span class="kn">from</span> <span class="nn">parlez.journal</span> <span class="kn">import</span> <span class="n">Entry</span>
<span class="kn">from</span> <span class="nn">sancho.utest</span> <span class="kn">import</span> <span class="n">UTest</span><span class="p">,</span> <span class="n">raises</span>

<span class="n">entry_text</span> <span class="o">=</span> <span class="s">&#39;&#39;&#39;This is a blog entry.</span><span class="se">\n\n</span><span class="s">*We hope you like it*.&#39;&#39;&#39;</span>

<span class="k">class</span> <span class="nc">EntryTest</span><span class="p">(</span><span class="n">UTest</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">init_test</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">Entry</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">entry_test</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">joe</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span><span class="s">&#39;joe&#39;</span><span class="p">)</span>
        <span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="p">()</span>
        <span class="n">e</span><span class="o">.</span><span class="n">set_author</span><span class="p">(</span><span class="n">joe</span><span class="p">)</span>
        <span class="c"># a string causes a TypeError, authors must be User instances</span>
        <span class="n">raises</span><span class="p">(</span><span class="ne">TypeError</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">set_author</span><span class="p">,</span> <span class="s">&#39;Joe&#39;</span><span class="p">)</span>
        <span class="k">assert</span> <span class="n">e</span><span class="o">.</span><span class="n">get_author</span><span class="p">()</span> <span class="o">==</span> <span class="n">joe</span>
        <span class="k">assert</span> <span class="n">e</span><span class="o">.</span><span class="n">get_created</span><span class="p">()</span> <span class="o">==</span> <span class="n">e</span><span class="o">.</span><span class="n">get_stamp</span><span class="p">()</span>
        <span class="n">e</span><span class="o">.</span><span class="n">set_text</span><span class="p">(</span><span class="n">entry_text</span><span class="p">)</span>
        <span class="k">assert</span> <span class="n">e</span><span class="o">.</span><span class="n">get_text</span><span class="p">()</span> <span class="o">==</span> <span class="n">entry_text</span>
        <span class="n">e</span><span class="o">.</span><span class="n">set_stamp</span><span class="p">()</span>
        <span class="k">assert</span> <span class="n">e</span><span class="o">.</span><span class="n">get_created</span><span class="p">()</span> <span class="o">!=</span> <span class="n">e</span><span class="o">.</span><span class="n">get_stamp</span><span class="p">()</span>

<span class="k">class</span> <span class="nc">JournalTest</span><span class="p">(</span><span class="n">UTest</span><span class="p">):</span>
    <span class="c"># we&#39;ll write this shortly, before Journal!</span>
    <span class="k">pass</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="n">EntryTest</span><span class="p">()</span>
    <span class="n">JournalTest</span><span class="p">()</span>
</pre></div>
<p>Run <tt class="docutils literal"><span class="pre">urun.py</span></tt> from the command line or from your editor and the result:</p>
<pre class="literal-block">
# /www/lib/parlez/test% urun.py
./utest_journal.py: EntryTest:
</pre>
<p>No tracebacks indicates successful test(s).</p>
<p>In part five of this series we'll start to write the HTML (remember, this
article series is apparently about web development with <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a>) and other user
interfaces for our Entry object.</p>
</div>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:469</guid>
  <pubDate>Mon, 04 Jun 2007 21:18:00 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
  <category>tutorial</category>
</item>
<item>
  <title>Python Web Application Diary, Part Three</title>
  <link>http://mikewatkins.ca/2007/06/04/python-web-application-diary-part-three/</link>
  <description><![CDATA[
<div class="document">
<p>In <a class="reference external" href="/tags/python/2007-06-02-23-23.html">part two</a> of this series we created a location and file system hierarchy
for application library objects, UI and other components, and did the same for
an actual application by using a script <a class="reference external" href="/software/files/qp/mkqpapp.py">mkqpapp.py</a> that automates those
tasks.</p>
<p>Today lets start writing code -- we'll begin by defining basic objects for
managing weblog or journal <em>entries</em>, and then we'll move on to showing how
<a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> and <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> make defining and publishing your Python objects as easy as,
well, py.</p>
<div class="section" id="basic-data-elements">
<h2>Basic Data Elements</h2>
<p>As discussed in <a class="reference external" href="/tags/python/2007-05-31-10-49.html">part one</a>, this tutorial / web application project will
result in a basic weblog or on-line journal application. Lets break down a
weblog into its most basic data elements:</p>
<ol class="arabic simple">
<li>A weblog is a collection of writing, generally presented in chronological
fashion. A weblog could be considered a diary or journal, so lets use the
term <strong>Journal</strong> to describe its function.</li>
<li>A journal usually, but not always, represents the thoughts and opinions of
a single author.</li>
<li>Each item in a journal can be considered an article or a post -
lets use a more generic term and call each item in the journal an
<strong>Entry</strong>.  Entries are typically short bits of text so lets enter and
store them as such. Each entry may have a title, and may include other
information including dates relating to when the Entry was created, made
available to readers, or changed -- but the principal information is the
entry itself.</li>
</ol>
</div>
<div class="section" id="our-first-classes">
<h2>Our first classes</h2>
<p>Turning to Python then, we could easily represent <strong>Entry</strong> as:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">Entry</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="n">title</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="n">text</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="n">created</span> <span class="o">=</span> <span class="bp">None</span>
</pre></div>
<p>We could then use the class:</p>
<div class="highlight"><pre><span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="p">()</span>
<span class="n">e</span><span class="o">.</span><span class="n">title</span> <span class="o">=</span> <span class="s">&#39;Python Web Application Diary, Part Three&#39;</span>
<span class="n">e</span><span class="o">.</span><span class="n">text</span> <span class="o">=</span> <span class="s">&#39;Hello, Bruce, my name is Bruce.&#39;</span>
<span class="n">created</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
</pre></div>
<p>That was pretty simple, no? Simplicity can be both a boon and a pain in the
butt, and experienced developers will recognize at least two significant
problems with our still too-simple <tt class="docutils literal"><span class="pre">Entry</span></tt> object:</p>
<ol class="arabic simple">
<li>There is no way of easily persisting this data (saving it so that its
available later when we need it)</li>
<li>The current design doesn't warn or otherwise prevent someone from
intentionally or accidentally storing data we don't expect, such as:</li>
</ol>
<div class="highlight"><pre><span class="n">e</span> <span class="o">=</span> <span class="n">Entry</span><span class="p">()</span>
<span class="n">e</span><span class="o">.</span><span class="n">title</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="n">e</span><span class="o">.</span><span class="n">created</span> <span class="o">=</span> <span class="s">&#39;Python Web Application Humour&#39;</span>
</pre></div>
</div>
<div class="section" id="kicking-entry-up-a-notch-persistence">
<h2>Kicking Entry Up a Notch - Persistence</h2>
<p>Lets first look at the issue of persistence. Keeping our journal entries
around for future display (or edits) could be done by:</p>
<ul class="simple">
<li>Saving the data into individual files</li>
<li>Saving the data in a relational (SQL) database such as Postgres, Oracle,
MySQL or MS SQL Server</li>
</ul>
<div class="section" id="to-sql-or-not-to-sql-that-is-the-question">
<h3>To SQL or not to SQL, that is the question</h3>
<p>Most often these days by default a developer will turn to a SQL database to
store and manage persistent data. While there is nothing wrong with this,
introducing SQL into the mix does complicate matters some what. SQL types are
not exactly analogous to Python data types, and accessing and updating data
held in a SQL repository can often require lots of tedious SQL code, in
addition to your Python code and objects.</p>
<p>To ease the friction or so-called <em>impedance</em> mismatch between Python and SQL,
various Object Relational Mappers (ORMs) have appeared on the Python scene.
While ORMs like SQLObject and SQL Alchemy do make using SQL-based data within
a Python application somewhat more convenient, its equally true that not all
applications need the added complexity and there are other alternatives which
can be useful to Python programmers <em>regardless</em> of complexity.</p>
<p><a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> doesn't enforce a particular data persistence approach upon a developer,
but it does make a choice for you which you can then consciously choose to
ignore.</p>
</div>
<div class="section" id="durus-a-python-object-database">
<h3>Durus, a Python Object Database</h3>
<p>Rather than deal with the impedance mismatch between Python and SQL, <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> by
default uses <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a>, a Python object database, to persist application data.</p>
<p>The truly neat thing about Durus, for Python users, is that you almost know
how to use it now, sight unseen.</p>
<p>Lets take our dirt-simple <tt class="docutils literal"><span class="pre">Entry</span></tt> object and make it database aware. You'll
recall the basic object looked like this:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">Entry</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="n">title</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="n">text</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="n">created</span> <span class="o">=</span> <span class="bp">None</span>
</pre></div>
<p>An <tt class="docutils literal"><span class="pre">Entry</span></tt> object able to participate in the <a class="reference external" href="http://www.mems-exchange.org/software/durus/">Durus</a> object database looks
like this:</p>
<div class="highlight"><pre><span class="k">class</span> <span class="nc">Entry</span><span class="p">(</span><span class="n">PersistentObject</span><span class="p">):</span>
    <span class="n">title</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="n">text</span> <span class="o">=</span> <span class="bp">None</span>
    <span class="n">created</span> <span class="o">=</span> <span class="bp">None</span>
</pre></div>
<p>As you can see, other than subclassing a special Durus type,
<tt class="docutils literal"><span class="pre">PersistentObject</span></tt>, there are no outward differences. We can therefore make
a straightforward claim: Durus is the database you already know.</p>
<p>We'll revisit Durus and object persistence in a future installment. In Part
Four of this series we shall take our too-simple, but persistent, object and
show how specifications can add useful constraints. We'll also take our first
look at <a class="reference external" href="http://www.mems-exchange.org/software/sancho/">Sancho</a>, a unit testing framework.</p>
</div>
</div>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:468</guid>
  <pubDate>Mon, 04 Jun 2007 18:33:00 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
  <category>tutorial</category>
</item>
</channel></rss>
