<?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/durus/</link>
  <atom:link href="http://mikewatkins.ca/tags/durus/feeds/rss" type="application/rss+xml" rel="self"/>
  <lastBuildDate>Thu, 04 Dec 2008 01:44:48 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>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" 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" 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" 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" 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 Database Interfaces</title>
  <link>http://mikewatkins.ca/2007/07/12/python-database-interfaces/</link>
  <description><![CDATA[
<div class="document">
<p><strong>Python object databases need some love too</strong></p>
<p>Flávio Coelho recently performed an examination of various Python database API
and ORM interfaces to MySQL, Postgres, and SQLite, and included a benchmark
for <a class="reference" href="http://docs.python.org/lib/module-cPickle.html">cPickle</a>.</p>
<p>Here's an addition to Flávio's  <a class="reference" href="http://pyinsci.blogspot.com/2007/07/fastest-python-database-interface.html">Fastest Python Database Interface</a> article and
script to include Durus: <a class="reference" href="http://64.21.147.49/durus/performance.py">performance.py</a>.</p>
<p>I also pointed out on Flávio's blog that his cPickle benchmark needed to
include pickling 100,000 &quot;Person&quot; classes, in addition to 100,000 simple
tuples - this to show the overhead of class instantiation and serialization /
deserialization which all of the ORM's and object databases share in some form
or another. An example of both can be found in <a class="reference" href="http://64.21.147.49/durus/performance.py">performance.py</a>.</p>
</div>

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


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

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">author</span><span class="p">):</span>
        <span class="n">Keyed</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
        <span class="n">Stamped</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
        <span class="n">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">author</span><span class="o">=</span><span class="n">author</span><span class="p">,</span> <span class="n">created</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">stamp</span><span class="p">,</span> <span class="n">published</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>

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

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

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

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

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

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

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

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

.h2 A subtitle

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

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

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

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

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

]]></description>
  <guid isPermaLink="false">tag:mikewatkins.ca,2007-10-10:journal:mw:entry:472</guid>
  <pubDate>Fri, 08 Jun 2007 15:44:00 GMT</pubDate>
  <category>durus</category>
  <category>python</category>
  <category>qp</category>
  <category>tutorial</category>
</item>
</channel></rss>