<?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/qp/</link>
  <atom:link href="http://mikewatkins.ca/tags/qp/feeds/rss" type="application/rss+xml" rel="self"/>
  <lastBuildDate>Tue, 25 Aug 2009 19:25:20 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>QP and Durus Updated</title>
  <link>http://mikewatkins.ca/2009/08/25/qp-and-durus-updated/</link>
  <description><![CDATA[
<div class="document">
<p>The folks at <a class="reference external" href="http://www.mems-exchange.org/software/">mems-exchange.org</a> released a <a class="reference external" href="http://mail.mems-exchange.org/durusmail/qp/453/">new version of the Python web application / site-management framework QP</a> and supporting packages.</p>
<p>All of today's released packages support Python &gt;= 2.4, which includes Python 3.1.</p>
<p>They also released an <a class="reference external" href="http://mail.mems-exchange.org/durusmail/durus-users/989/">update to Durus</a>, a compact and mature Python object database (which at its core operates like a minimal ZODB/ZEO work-a-like). The API to a Python object db is simply Python.</p>
<p>Key-value databases appear to be in vogue these days. Python developers with an interest in key-value databases may want to check out Durus (or ZODB): the key-value database you already know, <em>and more</em>.</p>
<p><em>More</em> means more than key-value pairs and simple types. More means virtually any Python object / type. More means more than simple string or integer keys  and simple values and offers not only persistent dictionaries but also persistent lists and sets, and persistent objects of most any design you may wish to implement.</p>
<p>Durus has no other package dependencies and is compact. Weighing in with less than 5000 lines of code it small enough to read in one sitting if you want to see how things tick. Or <a class="reference external" href="http://www.mems-exchange.org/software/durus/Durus-3.9.tar.gz/Durus-3.9/README.txt">you can just dive in</a> - start a server <tt class="docutils literal"><span class="pre">durus</span> <span class="pre">-s</span></tt> and a client <tt class="docutils literal"><span class="pre">durus</span> <span class="pre">-c</span></tt> and play.</p>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:715</guid>
  <pubDate>Tue, 25 Aug 2009 19:25:20 GMT</pubDate>
  <category>durus</category>
  <category>python</category>
  <category>qp</category>
</item>
<item>
  <title>Profiling QP applications</title>
  <link>http://mikewatkins.ca/2009/02/19/profiling-qp-applications/</link>
  <description><![CDATA[
<div class="document">
<p>Earlier this month <a class="reference external" href="http://plope.com/whatsitdoing2">Chris McDonough posted profile summaries</a> of four Python web frameworks: repoze.bfg, Django, Pylons, and Grok.</p>
<p>The framework I use, QP, supports WSGI but doesn't depend on it, which is neither good nor bad but perhaps as a result I'm a little less aware of the WSGI ecosystem than I should be so I am trying to find time to look at various middleware and application components.</p>
<p>Following up on Chris's post I took the <a class="reference external" href="http://pypi.python.org/pypi/repoze.profile">profiling middleware</a> from  <tt class="docutils literal"><span class="pre">repoze.profile</span></tt> for a spin to satisfy the latent WSGI curiosity percolating here under the covers. Using <tt class="docutils literal"><span class="pre">paste.httpserver</span></tt> failed for reasons I cannot at this time recall, yet driving the middleware and QP via the basic WSGI reference server was successful. I suppose I'll track that down when I have a real need.</p>
<p>Compared to the list of results in &quot;What's Your Web Framework Doing (2)&quot;, QP fits in with the Django results, returning 57 lines of profiler output for a simple GET request from a <em>hello, world</em> application.</p>
<p>I should point out that you can profile any QP application from the included interactive console which provides access to the profiler, as well as to the Durus Python object database containing your application's objects:</p>
<div class="highlight"><pre><span class="err">$</span> <span class="n">qp</span> <span class="o">-</span><span class="n">i</span> <span class="n">hello</span>
<span class="n">Profile</span><span class="p">,</span> <span class="n">publisher</span><span class="p">,</span> <span class="n">site</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">p</span> <span class="o">=</span> <span class="n">Profile</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">p</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">strip_dirs</span><span class="p">()</span>
<span class="o">&lt;</span><span class="n">pstats</span><span class="o">.</span><span class="n">Stats</span> <span class="n">instance</span> <span class="n">at</span> <span class="mf">0</span><span class="n">x875e7ac</span><span class="o">&gt;</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">p</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="s">&#39;time&#39;</span><span class="p">)</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">p</span><span class="o">.</span><span class="n">format</span><span class="p">()</span>
<span class="n">Wed</span> <span class="n">Feb</span> <span class="mf">18</span> <span class="mf">18</span><span class="p">:</span><span class="mf">08</span><span class="p">:</span><span class="mf">33</span> <span class="mf">2009</span>    <span class="o">/</span><span class="n">tmp</span><span class="o">/</span><span class="n">tmpQJy4QF</span><span class="o">.</span><span class="n">profile</span>

         <span class="mf">105</span> <span class="n">function</span> <span class="n">calls</span> <span class="ow">in</span> <span class="mf">0.007</span> <span class="n">CPU</span> <span class="n">seconds</span>

   <span class="n">Ordered</span> <span class="n">by</span><span class="p">:</span> <span class="n">internal</span> <span class="n">time</span>

   <span class="n">ncalls</span>  <span class="n">tottime</span>  <span class="n">percall</span>  <span class="n">cumtime</span>  <span class="n">percall</span> <span class="n">filename</span><span class="p">:</span><span class="n">lineno</span><span class="p">(</span><span class="n">function</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.004</span>    <span class="mf">0.004</span>    <span class="mf">0.006</span>    <span class="mf">0.006</span> <span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span><span class="p">:</span><span class="mf">1</span><span class="p">(</span><span class="o">&lt;</span><span class="n">module</span><span class="o">&gt;</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.001</span>    <span class="mf">0.001</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">375</span><span class="p">(</span><span class="n">write</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">now</span><span class="p">)</span>
        <span class="mf">5</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.001</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">320</span><span class="p">(</span><span class="n">generate_headers</span><span class="p">)</span>
       <span class="mf">12</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">utils</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">44</span><span class="p">(</span><span class="n">as_bytes</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.007</span>    <span class="mf">0.007</span> <span class="n">profile</span><span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">hit</span><span class="p">,</span> <span class="n">page</span> <span class="o">=</span> <span class="n">process</span><span class="p">())</span>
       <span class="mf">17</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="nb">isinstance</span><span class="p">)</span>
        <span class="mf">7</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">write</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">123</span><span class="p">(</span><span class="n">__init__</span><span class="p">)</span>
        <span class="mf">7</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">get</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.003</span>    <span class="mf">0.003</span> <span class="n">profiler</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">50</span><span class="p">(</span><span class="n">process</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">hit</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">32</span><span class="p">(</span><span class="n">init_response</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">request</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">202</span><span class="p">(</span><span class="n">get_header</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">request</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">105</span><span class="p">(</span><span class="n">__init__</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">request</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">330</span><span class="p">(</span><span class="n">_parse_pref_header</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.001</span>    <span class="mf">0.001</span> <span class="n">publish</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">94</span><span class="p">(</span><span class="n">process</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">common</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">61</span><span class="p">(</span><span class="n">site_now</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">setprofile</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.001</span>    <span class="mf">0.001</span> <span class="n">hit</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">25</span><span class="p">(</span><span class="n">__init__</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">239</span><span class="p">(</span><span class="n">set_body</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">request</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">306</span><span class="p">(</span><span class="n">get_encoding</span><span class="p">)</span>
        <span class="mf">2</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">spec</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">737</span><span class="p">(</span><span class="n">get_specified_attribute</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">rfc822</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">952</span><span class="p">(</span><span class="n">formatdate</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">slash</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">19</span><span class="p">(</span><span class="n">process_hit</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">request</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">373</span><span class="p">(</span><span class="n">parse_cookies</span><span class="p">)</span>
        <span class="mf">2</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">361</span><span class="p">(</span><span class="n">generate_body_chunks</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">156</span><span class="p">(</span><span class="n">set_status</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">293</span><span class="p">(</span><span class="n">get_content_length</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">common</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">23</span><span class="p">(</span><span class="n">get_publisher</span><span class="p">)</span>
        <span class="mf">2</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">items</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">300</span><span class="p">(</span><span class="n">_gen_cookie_headers</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">203</span><span class="p">(</span><span class="n">_compress_body</span><span class="p">)</span>
        <span class="mf">2</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="nb">getattr</span><span class="p">)</span>
        <span class="mf">2</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">144</span><span class="p">(</span><span class="n">set_compress</span><span class="p">)</span>
        <span class="mf">2</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">tz</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">60</span><span class="p">(</span><span class="n">dst</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">tz</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">40</span><span class="p">(</span><span class="n">now</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">228</span><span class="p">(</span><span class="n">_encode_chunk</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">sub</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">time</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">finditer</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">replace</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">split</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">gmtime</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">match</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">197</span><span class="p">(</span><span class="n">set_expires</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">tz</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">54</span><span class="p">(</span><span class="n">utcoffset</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">upper</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">getvalue</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">133</span><span class="p">(</span><span class="n">set_content_type</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">153</span><span class="p">(</span><span class="n">get_buffered</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">publish</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">484</span><span class="p">(</span><span class="n">get_time_zone</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">150</span><span class="p">(</span><span class="n">set_buffered</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="nb">len</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">lower</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">get_ident</span><span class="p">)</span>
        <span class="mf">1</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span>    <span class="mf">0.000</span> <span class="n">response</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mf">147</span><span class="p">(</span><span class="n">get_compress</span><span class="p">)</span>
        <span class="mf">0</span>    <span class="mf">0.000</span>             <span class="mf">0.000</span>          <span class="n">profile</span><span class="p">:</span><span class="mf">0</span><span class="p">(</span><span class="n">profiler</span><span class="p">)</span>
</pre></div>
<p>Nothing too surprising here nor is there much fluff. <tt class="docutils literal"><span class="pre">as_bytes</span></tt> (from the Durus package) gets called a number of times as from the same code base QP strives very hard to be a good Unicode citizen in both Python 2.x and 3.0+.</p>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:694</guid>
  <pubDate>Thu, 19 Feb 2009 21:21:08 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
</item>
<item>
  <title>Baby pylint alternative for py3k</title>
  <link>http://mikewatkins.ca/2009/02/19/baby-pylint-alternative-py3k-ready/</link>
  <description><![CDATA[
<div class="document">
<p>David Binger <a class="reference external" href="http://mail.mems-exchange.org/durusmail/qp/446/">noted on the QP list today</a> discussion on the <a class="reference external" href="http://mail.python.org/pipermail/python-dev/2009-February/086207.html">python-dev</a> list revolving around <tt class="docutils literal"><span class="pre">pylint</span></tt> being broken in Python 3 and suggests <tt class="docutils literal"><span class="pre">qpcheck.py</span></tt> as a baby pylint alternative.</p>
<ul class="simple">
<li>Current implementation of <a class="reference external" href="http://www.mems-exchange.org/software/qpy/qpy-1.7.tar.gz/qpy-1.7/qpcheck.py">qpcheck.py</a></li>
<li><a class="reference external" href="http://www.mems-exchange.org/software/qpy/">Qpy package</a> itself</li>
</ul>
<p>Running <tt class="docutils literal"><span class="pre">qpcheck.py</span> <span class="pre">|</span> <span class="pre">grep</span> <span class="pre">undefined</span></tt> against the Python 3 standard library returned almost 400 lines, at least some of which are actual errors.</p>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:693</guid>
  <pubDate>Thu, 19 Feb 2009 01:59:22 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
</item>
<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>First Python 3 Web Application Framework?</title>
  <link>http://mikewatkins.ca/2008/12/03/first-python-3-web-application-framework/</link>
  <description><![CDATA[
<div class="document">
<p>From the <a class="reference external" href="http://mail.mems-exchange.org/durusmail/qp/439/">QP mailing list, Wednesday December 3 2008</a>:</p>
<blockquote>
<p>Today the MEMS Exchange released updates of 5 software packages: Durus, QP, Qpy, Sancho, and Dulcinea.</p>
<p>You can find details and downloads at the usual location: <a class="reference external" href="http://www.mems-exchange.org/software/">http://www.mems-exchange.org/software/</a></p>
<p>These packages require Python 2.4 or higher, and yes, they even work with Python 3.0.</p>
</blockquote>
<p>It does seem that perhaps <tt class="docutils literal"><span class="pre">QP</span> <span class="pre">2.1</span></tt> and friends is among the first if not actually the first web and database development packages available on <a class="reference external" href="http://python.org/download/releases/3.0/">Python 3.0</a> which was released today.</p>
<p>(Previously I've written about QP's templating system, Qpy, and a performance <a class="reference external" href="http://mikewatkins.ca/2008/11/02/python-30-templating-observations/">increase</a> moving from Python 2.5 to 3.0.)</p>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:671</guid>
  <pubDate>Thu, 04 Dec 2008 01:44:48 GMT</pubDate>
  <category>durus</category>
  <category>python</category>
  <category>qp</category>
</item>
<item>
  <title>Python 3.0: Templating Observations</title>
  <link>http://mikewatkins.ca/2008/11/02/python-30-templating-observations/</link>
  <description><![CDATA[
<div class="document">
<p>Stumbling through Python-related posts on <a class="reference external" href="http://planet.python.org/">Planet Python</a> led me to a curious Python 3.0 discovery.</p>
<p>First I noted phililon wrote <a class="reference external" href="http://philikon.wordpress.com/2008/10/22/chameleon-byte-compiler-for-zpt-and-genshi/">Chameleon: byte compiler for ZPT and Genshi</a> (&quot;Fricken fast&quot;, apparently), which led me to <a class="reference external" href="http://code.google.com/p/spitfire/">Google Spitfire</a> (supposed to be even faster - it's certainly very fast on Python 2.5), which led me to <a class="reference external" href="http://code.google.com/p/spitfire/source/browse/trunk/tests/perf/bigtable.py">Google's implementation</a> of the Genshi <a class="reference external" href="http://genshi.edgewall.org/wiki/GenshiPerformance">bigtable.py</a> benchmark.</p>
<p>As I'm currently beta testing / porting my code base to be compatible with Python 3.0, and never having seen a performance test I didn't want to try or mangle the interpretation of, this naturally led me to check out my choice of web framework <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a>'s default template package <a class="reference external" href="http://www.mems-exchange.org/software/qpy/">Qpy</a> on Python 3.0.</p>
<p>Using the Google adaptation of the Genshi <tt class="docutils literal"><span class="pre">bigtable.py</span></tt> benchmark, I added an entry for QP; the benchmark results for packages which are included in or run on both Python 2.5 and Python 3.0 are interesting (<strong>update</strong> now including all the packages I have installed, Python 3.0 timing data derived from a run on RC3):</p>
<div class="highlight"><pre><span class="n">python2</span><span class="o">.</span><span class="mi">5</span> <span class="n">test</span><span class="o">/</span><span class="n">bigtable</span><span class="o">.</span><span class="n">py</span>
<span class="n">Genshi</span> <span class="n">tag</span> <span class="n">builder</span>                 <span class="mi">1465</span><span class="o">.</span><span class="mi">24</span> <span class="n">ms</span>
<span class="n">Genshi</span> <span class="n">template</span>                     <span class="mi">965</span><span class="o">.</span><span class="mi">37</span> <span class="n">ms</span>
<span class="n">Genshi</span> <span class="n">text</span> <span class="n">template</span>                <span class="mi">579</span><span class="o">.</span><span class="mi">29</span> <span class="n">ms</span>
<span class="n">Genshi</span> <span class="n">template</span> <span class="o">+</span> <span class="n">tag</span> <span class="n">builder</span>      <span class="mi">1558</span><span class="o">.</span><span class="mi">15</span> <span class="n">ms</span>
<span class="n">Mako</span> <span class="n">Template</span>                       <span class="mi">250</span><span class="o">.</span><span class="mi">65</span> <span class="n">ms</span>
<span class="n">ElementTree</span>                         <span class="mi">777</span><span class="o">.</span><span class="mi">58</span> <span class="n">ms</span>
<span class="n">Djange</span> <span class="n">template</span>                    <span class="mi">1175</span><span class="o">.</span><span class="mi">98</span> <span class="n">ms</span>
<span class="n">Spitfire</span> <span class="n">template</span>                   <span class="mi">112</span><span class="o">.</span><span class="mi">41</span> <span class="n">ms</span>
<span class="n">Spitfire</span> <span class="n">template</span> <span class="o">-</span><span class="n">O1</span>                <span class="mi">61</span><span class="o">.</span><span class="mi">18</span> <span class="n">ms</span>
<span class="n">Spitfire</span> <span class="n">template</span> <span class="o">-</span><span class="n">O2</span>                <span class="mi">28</span><span class="o">.</span><span class="mi">34</span> <span class="n">ms</span>
<span class="n">Spitfire</span> <span class="n">template</span> <span class="o">-</span><span class="n">O3</span>                <span class="mi">28</span><span class="o">.</span><span class="mi">43</span> <span class="n">ms</span>
<span class="n">cStringIO</span>                            <span class="mi">44</span><span class="o">.</span><span class="mi">26</span> <span class="n">ms</span>
<span class="n">StringIO</span>                            <span class="mi">151</span><span class="o">.</span><span class="mi">16</span> <span class="n">ms</span>
<span class="n">list</span> <span class="n">concat</span>                          <span class="mi">24</span><span class="o">.</span><span class="mi">10</span> <span class="n">ms</span>
<span class="n">QPY</span> <span class="n">Template</span>                        <span class="mi">136</span><span class="o">.</span><span class="mi">12</span> <span class="n">ms</span>

<span class="nv">%</span> <span class="nv">python3</span><span class="o">.</span><span class="mi">0</span> <span class="n">test</span><span class="o">/</span><span class="n">bigtable</span><span class="o">.</span><span class="n">py</span>
<span class="n">ElementTree</span>                         <span class="mi">449</span><span class="o">.</span><span class="mi">98</span> <span class="n">ms</span>
<span class="n">StringIO</span>                            <span class="mi">152</span><span class="o">.</span><span class="mi">47</span> <span class="n">ms</span>
<span class="n">list</span> <span class="n">concat</span>                          <span class="mi">22</span><span class="o">.</span><span class="mi">56</span> <span class="n">ms</span>
<span class="n">QPY</span> <span class="n">Template</span>                         <span class="mi">37</span><span class="o">.</span><span class="mi">89</span> <span class="n">ms</span>
</pre></div>
<p>Sadly there isn't much to compare Qpy to on py3k at present. Hopefully other web frameworks, including the big ones, are busy at work producing code compatible with Python 2.x and 3.0. My purpose for doing the comparison was to see if Python 3.0 had a material effect on other templating packages, not so much to compare functionality of say Django templates  to Qpy as their intended audience and feature set are so very different.</p>
<p>Incidentally the py3k improvement for Qpy represents a 71.3% speed-up for Qpy on Python 3.0rc1 over what was already amply quick on Python 2.5.1. Whatever the difference is, its not unique to Qpy: ElementTree also benefits greatly, turning in a 44.6% better performance.</p>
<p>These timings are done on an old desktop Unix workstation; more modern machines will turn in much better numbers but relatively speaking I believe these improvements will generally hold up.</p>
<p>On David Binger's Macbook Pro:</p>
<div class="highlight"><pre><span class="c"># py3k  22 ms</span>
<span class="c"># 2.5.1 55 ms</span>
<span class="kn">from</span> <span class="nn">timeit</span> <span class="kn">import</span> <span class="n">Timer</span>
<span class="k">print</span><span class="p">(</span><span class="n">Timer</span><span class="p">(</span><span class="s">&#39;qpy_template()&#39;</span><span class="p">,</span> <span class="s">&#39;from qpy.example.example2 import</span>
<span class="n">qpy_template</span><span class="s">&#39;).timeit(1000))</span>
</pre></div>
<p>Using timeit to get time for qpy_template() call:</p>
<pre class="literal-block">
25   ms  Python2.5.1 with quote.so
50   ms  Python2.5.1 without quote.so
11.7 ms  Python3.0 with quote.so
44   ms  Python 3.0 without quote.so

Compiled speedup is 25/11.7 = 2.1
Uncompiled speedup is 50/44 = 1.1
</pre>
<p>David also notes:</p>
<blockquote>
When using profile to test template execution, the it looks like we get a speedup from 254 ms to 199 ms per qpy_template() call between Python 2.5.1 and Python 3.0. Nothing in the profile jumps out at me as being responsible for the change.  The C code does, though, do some extra work for Python 2 to force the default encoding to be utf8.  Maybe that adds up to a significant amount of time.</blockquote>
<p>** Qpy?** The Qpy template model is going to look upside down if your experience or preference is with any of the many code-in-content template packages out there. Here's Qpy-enabled Python source compared to a couple of other templating approaches:</p>
<div class="highlight"><pre><span class="n">table</span> <span class="o">=</span> <span class="p">[</span><span class="nb">dict</span><span class="p">(</span><span class="n">a</span><span class="o">=</span><span class="mf">1</span><span class="p">,</span><span class="n">b</span><span class="o">=</span><span class="mf">2</span><span class="p">,</span><span class="n">c</span><span class="o">=</span><span class="mf">3</span><span class="p">,</span><span class="n">d</span><span class="o">=</span><span class="mf">4</span><span class="p">,</span><span class="n">e</span><span class="o">=</span><span class="mf">5</span><span class="p">,</span><span class="n">f</span><span class="o">=</span><span class="mf">6</span><span class="p">,</span><span class="n">g</span><span class="o">=</span><span class="mf">7</span><span class="p">,</span><span class="n">h</span><span class="o">=</span><span class="mf">8</span><span class="p">,</span><span class="n">i</span><span class="o">=</span><span class="mf">9</span><span class="p">,</span><span class="n">j</span><span class="o">=</span><span class="mf">10</span><span class="p">)</span>
      <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mf">1000</span><span class="p">)]</span>

<span class="c"># Qpy</span>
<span class="k">def</span> <span class="nf">qpy_template</span><span class="p">:</span><span class="n">xml</span><span class="p">():</span>
    <span class="s">&#39;&lt;table&gt;&#39;</span>
    <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">table</span><span class="p">:</span>
        <span class="s">&#39;&lt;tr&gt;&#39;</span>
        <span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">row</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="s">&#39;&lt;td&gt;</span><span class="si">%s</span><span class="s">&lt;/td&gt;&#39;</span> <span class="o">%</span> <span class="n">col</span>
        <span class="s">&#39;&lt;/tr&gt;&#39;</span>
    <span class="s">&#39;&lt;/table&gt;&#39;</span>

<span class="c"># Genshi</span>
<span class="k">def</span> <span class="nf">test_genshi</span><span class="p">():</span>
    <span class="n">stream</span> <span class="o">=</span>  <span class="n">MarkupTemplate</span><span class="p">(</span><span class="s">&quot;&quot;&quot;</span>
<span class="s">    &lt;table xmlns:py=&quot;http://genshi.edgewall.org/&quot;&gt;</span>
<span class="s">    &lt;tr py:for=&quot;row in table&quot;&gt;</span>
<span class="s">    &lt;td py:for=&quot;c in row.values()&quot; py:content=&quot;c&quot;/&gt;</span>
<span class="s">    &lt;/tr&gt;</span>
<span class="s">    &lt;/table&gt;&quot;&quot;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="n">table</span><span class="o">=</span><span class="n">table</span><span class="p">)</span>
    <span class="n">stream</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="s">&#39;html&#39;</span><span class="p">,</span> <span class="n">strip_whitespace</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>

<span class="c"># Django</span>
<span class="k">def</span> <span class="nf">test_django</span><span class="p">():</span>
    <span class="n">context</span> <span class="o">=</span> <span class="n">DjangoContext</span><span class="p">({</span><span class="s">&#39;table&#39;</span><span class="p">:</span> <span class="n">table</span><span class="p">})</span>
    <span class="n">DjangoTemplate</span><span class="p">(</span><span class="s">&quot;&quot;&quot;</span>
<span class="s">    &lt;table&gt;</span>
<span class="s">    {</span><span class="si">% f</span><span class="s">or row in table %}</span>
<span class="s">    &lt;tr&gt;{</span><span class="si">% f</span><span class="s">or col in row.values %}{{ col|escape }}{</span><span class="si">% e</span><span class="s">ndfor %}&lt;/tr&gt;</span>
<span class="s">    {</span><span class="si">% e</span><span class="s">ndfor %}</span>
<span class="s">    &lt;/table&gt;&quot;&quot;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>
</pre></div>
<p>Qpy makes writing quote-safe 'templates' as easy as writing Python code itself.</p>
<p>One of these days I'm sure to need a code-in-content solution and for raw performance alone the Cheetah inspired <a class="reference external" href="http://code.google.com/p/spitfire/">Google Spitfire</a> is sure to be on my list of packages to look at. But I hope that day doesn't come soon as I've grown rather fond of the content-in-code approach of Qpy which allows me to write Python code that looks like Python code.</p>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:633</guid>
  <pubDate>Mon, 03 Nov 2008 21:15:54 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
</item>
<item>
  <title>QP, lighttpd, SSL and SCGI</title>
  <link>http://mikewatkins.ca/2008/10/22/qp-lighttpd-ssl-and-scgi/</link>
  <description><![CDATA[
<div class="document">
<p>A version of <a class="reference external" href="http://www.mems-exchange.org/software/qp/">QP</a> supporting <a class="reference external" href="http://python.org/download/">Python</a> 3.0 (and prior Python versions of course) will be released when Python 3.0 soon hits the streets. While doing some testing I created a <a class="reference external" href="http://www.lighttpd.net/">lighttpd</a> configuration example illustrating setting up a virtual host with <a class="reference external" href="http://python.ca/scgi/">SCGI</a> (QP provides http and scgi servers natively) and SSL support:</p>
<div class="section" id="qp-with-lighttpd">
<h2>QP with lighttpd</h2>
<p>lighttpd is a lightweight web server that includes support for both SCGI and
SSL. As noted in the Apache configuration example regarding &quot;https_address&quot;
and &quot;as_http_address&quot;, the same caveats apply. If you find it necessary to
create a SSL &quot;pemfile&quot;:</p>
<pre class="literal-block">
$ cat server.key server.crt &gt; server.pem
</pre>
<p>The following are the minimum lighttpd.conf customizations required to
enable SCGI and set up a virtual host for http and https:</p>
<div class="highlight"><pre><span class="n">server</span><span class="o">.</span><span class="n">modules</span> <span class="o">=</span> <span class="p">(</span><span class="s">&quot;mod_access&quot;</span><span class="p">,</span>
                  <span class="s">&quot;mod_scgi&quot;</span><span class="p">,</span>
                  <span class="s">&quot;mod_accesslog&quot;</span><span class="p">)</span>

<span class="nv">$HTTP</span><span class="p">[</span><span class="s">&quot;host&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s">&quot;www.example.com&quot;</span> <span class="p">{</span>
    <span class="nv">$SERVER</span><span class="p">[</span><span class="s">&quot;socket&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s">&quot;0:443&quot;</span> <span class="p">{</span>
        <span class="n">ssl</span><span class="o">.</span><span class="n">engine</span> <span class="o">=</span> <span class="s">&quot;enable&quot;</span>
        <span class="n">ssl</span><span class="o">.</span><span class="n">pemfile</span> <span class="o">=</span> <span class="s">&quot;/my/ssl/server.pem&quot;</span>
        <span class="n">ssl</span><span class="o">.</span><span class="n">ca</span><span class="o">-</span><span class="n">file</span> <span class="o">=</span> <span class="s">&quot;/my/ssl/server.crt&quot;</span>
    <span class="p">}</span>
    <span class="n">scgi</span><span class="o">.</span><span class="n">server</span> <span class="o">=</span> <span class="p">(</span> <span class="s">&quot;&quot;</span> <span class="o">=&gt;</span>
        <span class="p">(</span> <span class="s">&quot;localhost&quot;</span> <span class="o">=&gt;</span>
            <span class="p">(</span> <span class="s">&quot;host&quot;</span> <span class="o">=&gt;</span> <span class="s">&quot;127.0.0.1&quot;</span><span class="p">,</span>
              <span class="s">&quot;port&quot;</span> <span class="o">=&gt;</span> <span class="mi">9000</span><span class="p">,</span>
              <span class="s">&quot;check-local&quot;</span> <span class="o">=&gt;</span> <span class="s">&quot;disable&quot;</span><span class="p">,</span>
              <span class="c1"># default disable-time is 60 seconds</span>
              <span class="s">&quot;disable-time&quot;</span> <span class="o">=&gt;</span> <span class="mi">5</span> <span class="c1"># seconds</span>
            <span class="p">)</span>
        <span class="p">)</span>
    <span class="p">)</span>
<span class="p">}</span>
</pre></div>
<div class="admonition-update admonition">
<p class="first admonition-title">Update</p>
<p>Wednesday November 12: After <a class="reference external" href="http://eric.themoritzfamily.com/2008/11/12/wsgi-benchmarking/">noting a post by Eric Mortiz</a> I put together a set of results comparing both Apache and lighttpd proxy and SCGI front ends to a QP web / SCGI server. My results seem different than Eric's:</p>
<pre class="literal-block">
==================================================
QP web server direct    2.38 [ms] (mean)
lighttpd 1.4.20
lighttpd proxy to QP    2.41 [ms] (mean)
lighttpd SCGI           2.31 [ms] (mean)

APACHE 1.3.41
APACHE 1.3 proxy to QP  3.39 [ms] (mean)
APACHE 1.3 mod_scgi     2.30 [ms] (mean)
==================================================
</pre>
<p class="last">Details in the <a class="reference external" href="/2008/10/22/qp-lighttpd-ssl-and-scgi/file/41b67fbe251d/">attached file</a></p>
</div>
</div>
</div>

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:618</guid>
  <pubDate>Wed, 22 Oct 2008 18:31:06 GMT</pubDate>
  <category>python</category>
  <category>qp</category>
</item>
</channel></rss>
