<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>oebfare: Latest Entries</title><link>http://oebfare.com/blog/</link><description /><language>en-us</language><lastBuildDate>Mon, 08 Dec 2008 10:12:28 -0600</lastBuildDate><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/oebfare-latest-entries" type="application/rss+xml" /><item><title>Gitify Python SVN</title><link>http://feedproxy.google.com/~r/oebfare-latest-entries/~3/r78JT37tXsg/</link><description>
&lt;p&gt;I love git. I try to do as much as I can using it. I have converted many SVN
based projects over to git so that I can interact with them more naturally.
I wanted a bit more of a challenge than just using &lt;code&gt;git svn clone&lt;/code&gt; to make
the repositories.&lt;/p&gt;
&lt;p&gt;I love Python. I use it all over the place such as web applications for one.
I want to some day be able to give back to Python in some form of a
contribution. Perhaps this is a first step. I tasked myself with moving
Python's SVN into git. Python has a pretty long history which makes it a bit
more tricky.&lt;/p&gt;
&lt;div class="section" id="going-local"&gt;
&lt;h2&gt;Going local&lt;/h2&gt;
&lt;p&gt;One approach that I can take is to use &lt;code&gt;git svn clone&lt;/code&gt; on the public SVN
URL, but that would take a very long time. It would be much better to have
access to actual repository and do a clone locally. Fortnately Python provides
the full repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;wget http://svn.python.org/snapshots/projects-svn-tarball.tar.bz2
tar xvfj projects-svn-tarball.tar.bz2
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This now gives us a diretory named &lt;code&gt;projects&lt;/code&gt; that is a bonafide SVN
repository. You can verify this by running:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;svn ls file:///Users/brian/code/python-svn/projects
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;The SVN path above is critical. The absolute path above is
&lt;code&gt;/Users/brian/code/python-svn/projects&lt;/code&gt;. This may be referenced
in other places, be sure to know what yours is if you are trying
accomplish something similar.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="gitify"&gt;
&lt;h2&gt;Gitify&lt;/h2&gt;
&lt;p&gt;Lets go ahead and begin the process of moving everything from SVN into git.
We simply use &lt;code&gt;git svn&lt;/code&gt; to handle this for us. It does a great job.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;git svn clone -s --prefix=svn/ file:///Users/brian/code/python-svn/projects/python
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We pass it &lt;code&gt;-s&lt;/code&gt; which indicates that the tree at the given URL follows the
standard SVN layout with &lt;code&gt;trunk&lt;/code&gt;, &lt;code&gt;branches&lt;/code&gt; and &lt;code&gt;tags&lt;/code&gt;. This helps git
see those and make them native. I always use &lt;code&gt;--prefix=svn/&lt;/code&gt; so that the
ref names for the SVN stuff gets prefixed and will avoid name clashing of
possible local branches.&lt;/p&gt;
&lt;p&gt;The above command will take a very long time to complete in this case. If the
SVN repository is small enough it will be relatively quick. It took about
five hours on my Macbook Pro.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="getting-our-hands-dirty"&gt;
&lt;h2&gt;Getting our hands dirty&lt;/h2&gt;
&lt;p&gt;Now we have a git repository of Python's SVN! However, we are not left with
some issues. We pulled down a nightly snapshot of the Python SVN repository.
We want to be able to keep it in sync the the on-going changes upstream.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git svn&lt;/code&gt; stores some of its information in &lt;code&gt;.git/config&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
[svn-remote &amp;quot;svn&amp;quot;]
    url = file:///Users/brian/code/python-svn/projects
    fetch = python/trunk:refs/remotes/svn/trunk
    branches = python/branches/*:refs/remotes/svn/*
    tags = python/tags/*:refs/remotes/svn/tags/*
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It seems logical that I can adjust the repository URL above and be able to
&lt;code&gt;git svn fetch&lt;/code&gt; without an issue. I have attempted this process several
times all to which failed in some sort of way giving me:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;Unable to determine upstream SVN information from working tree history
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, this one time it actually worked. The difference I am aware of
between this attempt and the previous attempts was the version of git I am
using. I am using git 1.6.0.4 which seems to handle this better. Perhaps
someone knows if there was indeed some fixes in regard to this.&lt;/p&gt;
&lt;p&gt;In my digging I found out that the reason why it would fail with the above
message is that &lt;code&gt;git svn&lt;/code&gt; is unable to automatically detect the repository
information from the commit messages. If you look at &lt;code&gt;git log&lt;/code&gt; you will see:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;commit a3e5b71ea1f27e29285c7a3e686e6084d10231a7
Author: benjamin.peterson &amp;lt;benjamin.peterson@6015fed2-1504-0410-9fe1-9d1591cc4771&amp;gt;
Date:   Sun Nov 23 02:09:41 2008 +0000

    raise a better error

    git-svn-id: file:///Users/brian/code/python-svn/projects/python/trunk@67348 6015fed2-1504-0410-9fe1-9d1591cc4771
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice the &lt;code&gt;git-svn-id&lt;/code&gt; part. This has meaning to &lt;code&gt;git svn&lt;/code&gt;. Rememeber
before how I told you that the full path was important? My end goal for this
task was to make this repository available. I need to change this in all
commits.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="git-filter-branch-is-really-poweful"&gt;
&lt;h2&gt;&lt;code&gt;git filter-branch&lt;/code&gt; is really poweful&lt;/h2&gt;
&lt;p&gt;Maybe too powerful? git comes with &lt;code&gt;filter-branch&lt;/code&gt; that enables you to
completely rewrite a branch commit history. This is pretty insane. I wanted
to adjust the commit messages to contain the correct path in git-svn-id.&lt;/p&gt;
&lt;p&gt;Lets break out some &lt;code&gt;sed&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt; awesomeness here:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;git filter-branch \
    --msg-filter \
        &amp;#39;sed -e &amp;quot;s/^git-svn-id: file:\/\/\/Users\/brian\/code\/python-svn\//git-svn-id: http:\/\/svn.python.org\//g&amp;quot;&amp;#39; \
    $(cat .git/packed-refs | awk &amp;#39;// {print $2}&amp;#39; | grep -v &amp;#39;pack-refs&amp;#39;)
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will rewrite the entire repository history adjusting the commit messages
by changing &lt;code&gt;file:///Users/brian/code/python-svn/&lt;/code&gt; to
&lt;code&gt;http://svn.python.org/&lt;/code&gt;. Credit goes to &lt;a class="reference external" href="http://translate.org.za/blogs/wynand/en/content/changing-your-svn-repository-address-git-svn-setup"&gt;this blog&lt;/a&gt; where I ripped the
above command off. That blogger goes into more detail and I recommend the
read.&lt;/p&gt;
&lt;p&gt;Once again, the above command is going to take a very long time in this case.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="ta-da"&gt;
&lt;h2&gt;Ta da!&lt;/h2&gt;
&lt;p&gt;The very last step in this process is to kill &lt;code&gt;.git/svn&lt;/code&gt;. I figured at first
that I didn't need to do this, but &lt;code&gt;git svn rebase&lt;/code&gt; was taking forever. Did
this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;rm -rf .git/svn
git svn rebase --all
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And viola! All is working now.&lt;/p&gt;
&lt;p&gt;I worked with &lt;a class="reference external" href="http://jannisleidel.com/"&gt;Jannis Leidel&lt;/a&gt; to get the repository auto-updating and
publically available. You can clone it from &lt;a class="reference external" href="http://github.com/python-git/python/tree/master"&gt;GitHub&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;git clone git://github.com/python-git/python.git
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I hope I was able to help out someone and provide a place where more people
can contribute back to Python using git. Do keep in mind this git mirror is
unofficial and all patches should be directed upstream to the Python
developers.&lt;/p&gt;
&lt;/div&gt;
</description><pubDate>Mon, 08 Dec 2008 10:12:28 -0600</pubDate><guid isPermaLink="false">http://oebfare.com/blog/2008/dec/08/gitify-python-svn/</guid><feedburner:origLink>http://oebfare.com/blog/2008/dec/08/gitify-python-svn/</feedburner:origLink></item><item><title>Git Tab Complete</title><link>http://feedproxy.google.com/~r/oebfare-latest-entries/~3/WHpUhi5t_W4/</link><description>
&lt;p&gt;One thing that has bothered my about git was the lack of tab complete. Well,
this was completely my fault. It turns out that in the git source tree in
their &lt;code&gt;contrib&lt;/code&gt; directory is tab complete bash script! Here is how I installed it and
made my life 75.6 times easier:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;cd GIT_SRC/contrib/completion
cp git-completion.bash ~/bin
echo &amp;quot;source ~/bin/git-completion.bash&amp;quot; &amp;gt;&amp;gt; ~/.profile
source ~/.profile
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Viola.&lt;/p&gt;
</description><pubDate>Fri, 14 Nov 2008 11:16:22 -0600</pubDate><guid isPermaLink="false">http://oebfare.com/blog/2008/nov/14/git-tab-complete/</guid><feedburner:origLink>http://oebfare.com/blog/2008/nov/14/git-tab-complete/</feedburner:origLink></item><item><title>Book Memery</title><link>http://feedproxy.google.com/~r/oebfare-latest-entries/~3/bCXZodfVM50/</link><description>
&lt;p&gt;Doing this thing.&lt;/p&gt;
&lt;blockquote&gt;
The guard &lt;code&gt;GuardExpr1&lt;/code&gt;, &lt;code&gt;GuardExpr2&lt;/code&gt;, &lt;code&gt;...&lt;/code&gt;, &lt;code&gt;GuardExprN&lt;/code&gt; is
&lt;code&gt;true&lt;/code&gt; if all the guard expressions -- &lt;code&gt;GuardExpr1&lt;/code&gt;, &lt;code&gt;GuardExpr2&lt;/code&gt;,
&lt;code&gt;...&lt;/code&gt; -- evaluate to true.&lt;/blockquote&gt;
&lt;p&gt;Via &lt;a class="reference external" href="http://readernaut.com/brosner/books/193435600X/"&gt;Programming Erlang&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Grab the nearest book.&lt;/li&gt;
&lt;li&gt;Open it to page 56.&lt;/li&gt;
&lt;li&gt;Find the fifth sentence.&lt;/li&gt;
&lt;li&gt;Post the text of the sentence in your journal along with these
instructions.&lt;/li&gt;
&lt;li&gt;Don't dig for your favorite book, the cool book, or the intellectual one:
pick the CLOSEST.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Saw this on &lt;a class="reference external" href="http://justinlilly.com/blog/2008/nov/12/book-memery/"&gt;Justin Lilly&lt;/a&gt;'s and &lt;a class="reference external" href="http://www.20seven.org/journal/2008/11/book-meme.html"&gt;Greg Newman&lt;/a&gt;'s blog.&lt;/p&gt;
</description><pubDate>Wed, 12 Nov 2008 13:11:05 -0600</pubDate><guid isPermaLink="false">http://oebfare.com/blog/2008/nov/12/book-memery/</guid><feedburner:origLink>http://oebfare.com/blog/2008/nov/12/book-memery/</feedburner:origLink></item><item><title>Multiple Foreign Keys to Same Model for Inlines</title><link>http://feedproxy.google.com/~r/oebfare-latest-entries/~3/rJmG2GjrI6s/</link><description>
&lt;p&gt;When you are working with a model that has more than one foreign key to the
same model and you want to inline that model you will run into problems. The
reason why is due to the way &lt;code&gt;inlineformset_factory&lt;/code&gt; works. By default it
can work out what foreign key on the given model is referenced to the parent.
Lets look how you might call &lt;code&gt;inlineformset_factory&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;BookFormSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inlineformset_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Book&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above case is simple. In all likelyhood you will only have one foriegn key
to &lt;code&gt;Author&lt;/code&gt;. Lets look at a more complex scenerio:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Friendship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;from_friend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;related_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;friend_set&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;to_friend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;related_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;otherside&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The models above show a more complex case of something you might want to
inline. The above &lt;code&gt;Friendship&lt;/code&gt; model would likely have more fields to make
the inline worth something. Now lets look at how you might construct the
inline formset for this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;FriendshipInline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inlineformset_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Friendship&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fk_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;from_friend&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We have explicitly given a &lt;code&gt;fk_name&lt;/code&gt; because by default
&lt;code&gt;inlineformset_factory&lt;/code&gt; would not have known which foriegn key you intend to
use to &lt;code&gt;Person&lt;/code&gt;.&lt;/p&gt;
&lt;div class="section" id="side-note"&gt;
&lt;h2&gt;Side Note&lt;/h2&gt;
&lt;p&gt;I did have a two day hiatus in my blogging, but I will make up for those,
I promise.&lt;/p&gt;
&lt;/div&gt;
</description><pubDate>Mon, 10 Nov 2008 23:26:39 -0600</pubDate><guid isPermaLink="false">http://oebfare.com/blog/2008/nov/10/multiple-foreign-keys-same-model-inlines/</guid><feedburner:origLink>http://oebfare.com/blog/2008/nov/10/multiple-foreign-keys-same-model-inlines/</feedburner:origLink></item><item><title>App Settings</title><link>http://feedproxy.google.com/~r/oebfare-latest-entries/~3/druZhuOqzOc/</link><description>
&lt;p&gt;In my recent &lt;a class="reference external" href="http://oebfare.com/blog/2008/nov/04/reusable-app-conventions/"&gt;reusable apps conventions&lt;/a&gt; post there was a comment by
Devin Naquin who brought up app settings. I replied saying that it was one
thing I didn't discuss, but wanted to revisit in another blog post. This will
be that post.&lt;/p&gt;
&lt;p&gt;There are times where an app needs to have some value defined by the user.
However obtaining this value is somewhat not very clear. Django projects have
a &lt;code&gt;settings.py&lt;/code&gt; module that stores settings that a site developer might
want to adjust based on the site or server. I believe this is the best place
to store app settings. There has been some discussion in the Pinax community
regarding the need of multiple levels of settings files. This would allow a
seperation between global, site-specific and installation specific settings.&lt;/p&gt;
&lt;div class="section" id="looking-at-project-settings"&gt;
&lt;h2&gt;Looking at project settings&lt;/h2&gt;
&lt;p&gt;Lets step back a little and take a look at the &lt;code&gt;settings.py&lt;/code&gt; file that you
use to modify the project's settings. This file can really be divided it up.
It is ideal that the file straight out of &lt;code&gt;startapp&lt;/code&gt; is not committed into
your own version control. The reasoning is due to some settings having either
sensitive info (if it is a public repository) or they are almost always going
to be changed in different checkouts. One of the common ways of dealing with
this is to break out the installation specific settings from the more global
ones that are more project level. Most users will simply add this bit to the
end of the &lt;code&gt;settings.py&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;local_settings&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;ImportError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This enables a file named &lt;code&gt;local_settings.py&lt;/code&gt; to contain setting overrides
to the main settings. This is done at the end of the file to allow for the
overriding of global variables. This works well and can go a long way.&lt;/p&gt;
&lt;p&gt;The reason why this is important to app settings is that if you are
distributing your app as reusable you might want to encourage this way of
handling settings. Users can add settings that may be installation specific
such as api keys, file system paths, etc.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="naming-conventions"&gt;
&lt;h2&gt;Naming conventions&lt;/h2&gt;
&lt;p&gt;The way I normally handle this is to prefix the setting with the app name.
For example in &lt;a class="reference external" href="http://code.google.com/p/django-mailer/"&gt;django-mailer&lt;/a&gt; users have the ability to control how long
it sleeps in a daemon mode before querying the database. It is named
&lt;code&gt;MAILER_QUEUE_SLEEP&lt;/code&gt;. This helps to easily distiquish this setting from
others ones.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="getting-the-values-and-dealing-with-optional-settings"&gt;
&lt;h2&gt;Getting the values and dealing with optional settings&lt;/h2&gt;
&lt;p&gt;When it comes time to needing the value of a particular setting you will
need to get it. Django provides a proxy class between the &lt;code&gt;settings.py&lt;/code&gt; and
the code that references them. Here is how you might grab the value of the
setting I mentioned above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="n"&gt;QUEUE_SLEEP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;MAILER_QUEUE_SLEEP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The other bit of naming conventions is that your name the variable that you
bind the data to locally as the setting name without the app name to prefix
it since it is implied. When the user does not provide &lt;code&gt;MAILER_QUEUE_SLEEP&lt;/code&gt;
this will raise an &lt;code&gt;AttributeError&lt;/code&gt; exception. I see this has an expected
error if the setting is required.&lt;/p&gt;
&lt;p&gt;If you need the ability to make the setting optional where you provide a
sensible default you can do that very easily:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;QUEUE_SLEEP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;MAILER_QUEUE_SLEEP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;getattr&lt;/code&gt; takes an optional third parameter that will be returned in the
event the second parameter is not found on the first parameter. This makes it
very simple to give a sensible default when not provided, but also allow the
user to override the default through the standard way.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="wrapping-up"&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;I feel this is the best way to deal with app settings. This is drop dead
simple and effective. However, there are places where things could be
improved. What if an app wanted to allow the end-user to define different
parameters? Good question and it sounds like it would make an excellent
reusable app to handle that.&lt;/p&gt;
&lt;/div&gt;
</description><pubDate>Fri, 07 Nov 2008 23:01:43 -0600</pubDate><guid isPermaLink="false">http://oebfare.com/blog/2008/nov/07/app-settings/</guid><feedburner:origLink>http://oebfare.com/blog/2008/nov/07/app-settings/</feedburner:origLink></item><item><title>Essentials</title><link>http://feedproxy.google.com/~r/oebfare-latest-entries/~3/AonwKb6yHt8/</link><description>
&lt;p&gt;I am going to cheat a little today and go for a simple post. I have some good
content coming this weekend. This post will cover the tools I use everyday.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;OS X 10.5.5&lt;/li&gt;
&lt;li&gt;Colloquy&lt;/li&gt;
&lt;li&gt;Safari&lt;/li&gt;
&lt;li&gt;Twitterific&lt;/li&gt;
&lt;li&gt;Textmate&lt;/li&gt;
&lt;li&gt;Skype&lt;/li&gt;
&lt;li&gt;Skitch&lt;/li&gt;
&lt;li&gt;Cord&lt;/li&gt;
&lt;li&gt;Adium&lt;/li&gt;
&lt;li&gt;iTunes&lt;/li&gt;
&lt;li&gt;rsync&lt;/li&gt;
&lt;li&gt;git&lt;/li&gt;
&lt;li&gt;VMWare Fusion&lt;/li&gt;
&lt;li&gt;NetNewsWire&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Those are the pretty typical OS X apps one would expect. Just to juice up this
post a bit let me share a bit from my &lt;code&gt;~/.profile&lt;/code&gt;. Thanks to &lt;a class="reference external" href="http://justinlilly.com/"&gt;Justin Lilly&lt;/a&gt;
who cooked up this gem:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;NORMAL=&amp;#39;\[\033[00m\]&amp;#39;
BGREEN=&amp;#39;\[\033[1;32m\]&amp;#39;
BBLUE=&amp;#39;\[\033[1;34m\]&amp;#39;
GREEN=&amp;#39;\[\033[0;32m\]&amp;#39;

parse_git_branch() {
    git branch 2&amp;gt; /dev/null | sed -e &amp;#39;/^[^*]/d&amp;#39; -e &amp;#39;s/* \(.*\)/\1 /&amp;#39;;
}
parse_svn_rev() {
    svn info 2&amp;gt; /dev/null | grep &amp;quot;Revision&amp;quot; | sed &amp;#39;s/Revision: \(.*\)/r\1 /&amp;#39;;
}

export PS1=&amp;quot;${BGREEN}\u@\h ${GREEN}\$(parse_git_branch)\$(parse_svn_rev)${BBLUE}[${NORMAL}\w${BBLUE}]\n${BBLUE}$ ${NORMAL}&amp;quot;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will render your PS1 as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;brian@brosner-osx master [~/Development/twid/twid]
$
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Colors won't show, but you get the idea. Also here are some aliases I use:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;alias gst=&amp;#39;git status&amp;#39;
alias gl=&amp;#39;git pull&amp;#39;
alias gp=&amp;#39;git push&amp;#39;
alias gd=&amp;#39;git diff | mate&amp;#39;
alias gc=&amp;#39;git commit -v&amp;#39;
alias gca=&amp;#39;git commit -v -a&amp;#39;
alias gb=&amp;#39;git branch&amp;#39;
alias gba=&amp;#39;git branch -a&amp;#39;
alias gsr=&amp;#39;git svn rebase&amp;#39;

alias gho=&amp;#39;$(git remote -v | grep github | sed -e &amp;quot;s/.*git\:\/\/\([a-z]\.\)*/\1/&amp;quot; -e &amp;quot;s/\.git$//g&amp;quot; -e &amp;quot;s/.*@\(.*\)$/\1/g&amp;quot; | tr &amp;quot;:&amp;quot; &amp;quot;/&amp;quot; | tr -d &amp;quot;\011&amp;quot; | sed -e &amp;quot;s/^/open http:\/\//g&amp;quot;)&amp;#39;

alias delpyc=&amp;#39;find . -name &amp;quot;*.pyc&amp;quot; -exec rm -fv {} \;&amp;#39;
alias deljyc=&amp;#39;find . -name &amp;quot;*$py.class&amp;quot; -exec rm -v {} \;&amp;#39;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;gho&lt;/code&gt; alias was another one from Justin Lilly. I haven't actually used
it a ton, but in theory will open a &lt;a class="reference external" href="http://github.com"&gt;GitHub&lt;/a&gt; repository page for the given
repository you are in.&lt;/p&gt;
</description><pubDate>Thu, 06 Nov 2008 22:18:44 -0600</pubDate><guid isPermaLink="false">http://oebfare.com/blog/2008/nov/06/essentials/</guid><feedburner:origLink>http://oebfare.com/blog/2008/nov/06/essentials/</feedburner:origLink></item><item><title>Moving away from Google Code</title><link>http://feedproxy.google.com/~r/oebfare-latest-entries/~3/g2-TEBk0o6g/</link><description>
&lt;p&gt;Over in Pinax land we have recently moved away from using Google Code. Google
provides project hosting for open source projects. It really is a valuable
service for anyone with an open source project. They provide a web interface
that includes a wiki, issue tracking, SVN browser and a bit more.&lt;/p&gt;
&lt;p&gt;Pinax lived under the project name &lt;a class="reference external" href="http://code.google.com/p/django-hotclub/"&gt;django-hotclub&lt;/a&gt; on Google Code. It mostly
still does. We were sort of outgrowing the features Google Code was providing
us. Utlimately we wanted to write our own software development platform using
Pinax so it seemed to be the best time, early in the project, to move the
version code system elsewhere.&lt;/p&gt;
&lt;div class="section" id="step-one"&gt;
&lt;h2&gt;Step One&lt;/h2&gt;
&lt;p&gt;The first step in this process is to get a local copy of the Subversion
repository. I first created a local SVN repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;svnadmin create /home/brian/svn/pinax
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;SVN has a handy tool named &lt;code&gt;svnsync&lt;/code&gt;. The first thing I did was initialize
the repository for using &lt;code&gt;svnsync&lt;/code&gt;. I simply executed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;svnsync init file:///home/brian/svn/pinax/ https://django-hotclub.googlecode.com/svn/
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This fails with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;svnsync: Repository has not been enabled to accept revision propchanges;
ask the administrator to create a pre-revprop-change hook
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I enabled this hook by simply moving the template hook to a real hook and
making it executable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;mv /home/brian/pinax/hooks/pre-revprop-change.tmpl /home/brian/pinax/hooks/pre-revprop-change
chmod +x /home/brian/pinax/hooks/pre-revprop-change
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The Pinax repository sets more props than what the hook allows (this is my
best guess as to why) so I needed to modify the hook a tiny bit to allow any
revprop change. I simply changed the the exit value in the one error case to
return a &lt;code&gt;0&lt;/code&gt; status code so &lt;code&gt;svnsync&lt;/code&gt; thinks it works.&lt;/p&gt;
&lt;p&gt;Once this is all set I was able to run the sync:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;svnsync sync file:///home/brian/svn/pinax/
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It was on a roll.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="step-two"&gt;
&lt;h2&gt;Step Two&lt;/h2&gt;
&lt;p&gt;Step two was to remap the usernames that were in Google Code to ones the
committers normally go by. How on earth am I going to do this? I searched
high and low on the Internet to see if there was some simple way. I could not
find anything. &lt;a class="reference external" href="http://jtauber.com/"&gt;James Tauber&lt;/a&gt; mentioned that the dump file you can get from
SVN is plain text. This sparked an idea. Why not handle this before
re-importing it. James said that the only way to set it up correctly on
Webfaction was to dump from my synced repository and re-import it. This made
the dump/import a requirement.&lt;/p&gt;
&lt;p&gt;The next step was to learn how the file format is layed out. While I was
searching the web I happened to come across a Python script that can
read/write dump files. This was perfect. I don't have this source available,
but once I find it I will give proper credit. It was a bit dated in terms
of Python code so I rewrote it. It was a good opportunity to actually learn
how it works.&lt;/p&gt;
&lt;p&gt;After spending two/three hours rewriting it and understanding how it works
I was successfully able to parse the dump file and remap the usernames to
what we desired.&lt;/p&gt;
&lt;p&gt;Here is the final script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;copy&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;cStringIO&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StringIO&lt;/span&gt;

&lt;span class="n"&gt;username_mapping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;leidel&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;jezdez&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;floguy&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;ericflo&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;&amp;quot;gregoryjnewman&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;newman&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Lump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrlist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;proplist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;propdict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sethdr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrlist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delhdr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrlist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_rfc822_headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;lump&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Lump&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="c"&gt;# eof&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrlist&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="c"&gt;# newline after headers ends them&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="c"&gt;# newline before headers is simply ignored&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;colon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;colon&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;colon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;colon&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;: &amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;colon&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;colon&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
        &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sethdr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;props_parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;proplist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;propdict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;K &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;need_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;D &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;need_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;PROPS-END&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Unrecognized record in props section&amp;quot;&lt;/span&gt;

        &lt;span class="c"&gt;# the position of the \n character&lt;/span&gt;
        &lt;span class="n"&gt;nl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;nl&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;
        &lt;span class="c"&gt;# length of the key&lt;/span&gt;
        &lt;span class="n"&gt;kl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;kl&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="c"&gt;# key value&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;kl&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="c"&gt;# move the index position&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;kl&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;need_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;V &amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;nl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;nl&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;vl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;vl&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;vl&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;vl&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
        &lt;span class="n"&gt;proplist&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;propdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;proplist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;propdict&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_lump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;lump&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_rfc822_headers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;pcl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Prop-content-length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;tcl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Text-content-length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pcl&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;proplist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;propdict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;props_parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pcl&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tcl&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tcl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write_lump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;lump&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deepcopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prop_stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StringIO&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;proplist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;proplist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;propdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;prop_stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;D &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="n"&gt;prop_stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c"&gt;# write key out&lt;/span&gt;
                &lt;span class="n"&gt;prop_stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;K &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="n"&gt;prop_stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="c"&gt;# write value out&lt;/span&gt;
                &lt;span class="n"&gt;prop_stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;V &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="n"&gt;prop_stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;prop_stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;PROPS-END&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prop_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prop_stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getvalue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sethdr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Prop-content-length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop_data&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delhdr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Prop-content-length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# TODO: if lump.text_data ever changes we need to write out a new&lt;/span&gt;
    &lt;span class="c"&gt;# Text-content-md5&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sethdr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Text-content-length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_data&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delhdr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Text-content-length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sethdr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Content-length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_data&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delhdr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Content-length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# TODO: need a better data strucuture here for a sorted dict&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrlist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;# write prop data&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;# the text data was not modified so just write it to the stream&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Prop-content-length&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; \
         &lt;span class="s"&gt;&amp;quot;Text-content-length&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; \
         &lt;span class="s"&gt;&amp;quot;Content-length&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert_username&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;svn:author&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;propdict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;propdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;svn:author&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;username_mapping&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;committer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;username_mapping&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;propdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;svn:author&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;committer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;propdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;svn:author&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;propdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;svn:author&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;committer&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;
    &lt;span class="n"&gt;new_fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;

    &lt;span class="c"&gt;# read headers up until a revision&lt;/span&gt;
    &lt;span class="n"&gt;lump&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_lump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Revision-number&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;# write the lump to disk&lt;/span&gt;
        &lt;span class="n"&gt;write_lump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;lump&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_lump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;revhdr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;revhdr&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;# read revision header&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Revision-number&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;revhdr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;processing r&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;revhdr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Revision-number&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],)&lt;/span&gt;
        &lt;span class="n"&gt;revhdr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convert_username&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;revhdr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="c"&gt;# read revision contents&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;lump&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_lump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Revision-number&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hdrdict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;newrevhdr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;# write out the revision&lt;/span&gt;
        &lt;span class="n"&gt;write_lump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;revhdr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;write_lump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lump&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;revhdr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newrevhdr&lt;/span&gt;

    &lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;new_fp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="svn-commit-blog-post"&gt;
&lt;h2&gt;&lt;code&gt;svn commit blog-post&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;I hope someone out there finds this useful. Rewriting to understand the script
above was an absolute blast. Maybe you can provide ways to improve it. I
didn't spend too much time thinking about improving it.&lt;/p&gt;
&lt;/div&gt;
</description><pubDate>Wed, 05 Nov 2008 21:28:46 -0600</pubDate><guid isPermaLink="false">http://oebfare.com/blog/2008/nov/05/moving-away-google-code/</guid><feedburner:origLink>http://oebfare.com/blog/2008/nov/05/moving-away-google-code/</feedburner:origLink></item><item><title>Reusable App Conventions</title><link>http://feedproxy.google.com/~r/oebfare-latest-entries/~3/TO7sF1LgOzA/</link><description>
&lt;p&gt;One of the great strengths of Django is the vast ecosystem of reusable apps.
People saw common patterns in what they were making and abstracted those out
in to an app that anyone else can use in their own projects. The &lt;a class="reference external" href="http://pinaxproject.com/"&gt;Pinax&lt;/a&gt;
project, in which I am a committer, is attempting to take the ecosystem and
bundle up these reusable apps into more of a deliverable. We are working on
having different flavors of Pinax that will suit what you are trying to do.
This also doesn't mean you couldn't pick and choose your own apps.&lt;/p&gt;
&lt;p&gt;I want to take the time in this post to go over conventions that should be
established for reusable apps and Django apps in general.&lt;/p&gt;
&lt;div class="section" id="reusable-vs-non-reusable-apps"&gt;
&lt;h2&gt;Reusable vs Non-Reusable Apps&lt;/h2&gt;
&lt;p&gt;A reusable app is meant to do one thing and do it well. The second it cross
the boundary of doing more than one thing you need to question yourself
whether or not what you are adding is appropriate. Should that one new
feature really be contained in its own app to flourish and grow on its own?&lt;/p&gt;
&lt;div class="section" id="a-story"&gt;
&lt;h3&gt;A Story&lt;/h3&gt;
&lt;p&gt;A good case of where I really began to question myself was during the
development of &lt;a class="reference external" href="http://code.google.com/p/django-categories/"&gt;django-categories&lt;/a&gt;. I started the project a little over a
year ago. This was literally just before &lt;a class="reference external" href="http://djangopeople.net/insin/"&gt;Jonathan Buchanan&lt;/a&gt; started to take
some ideas on the Django wiki and dump them into what we now know as
&lt;a class="reference external" href="http://code.google.com/p/django-mptt/"&gt;django-mptt&lt;/a&gt;. At the time I was just learning about MPTT and how it can
benefit me in storing trees in a relational database. I was tasked with the
need to create categories at work so it felt like the right thing to use.&lt;/p&gt;
&lt;p&gt;I started to write django-categories in a reusable way. I used a parent
foreign key to deal with the hierarchy. It quickly became apparent that the
data set I had was a bit too large for some of queries I was doing using a
simple parent foreign key. I started to re-work django-categories to include
the denormalization that MPTT provides. Right then django-mptt came out. I was
simply attonished by how well implemented it was. It stayed out of your way.&lt;/p&gt;
&lt;p&gt;At this point I had two choices. One, use django-mptt having a dependancy on
another reusable app. Two, continue on having on my own implementation of
MPTT that was really lacking. I can't say for sure that this is a case of
doing more than one thing, but it certainly broad sided me (in a good way) in
understanding where lines can be drawn.&lt;/p&gt;
&lt;p&gt;I ultimately just closed the project due to my particular use case and
pointed people to django-mptt. However, recently I have come across a few
cases where having an app that provided a &lt;code&gt;Category&lt;/code&gt; model, a URLconf, views
and some feeds around generically relating objects to a tree is a good idea.
I have since reopened the project and moving forward with it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="drawing-the-lines"&gt;
&lt;h3&gt;Drawing the lines&lt;/h3&gt;
&lt;p&gt;The case I show above was specific to my needs, these things need to be
thought of on your own. If you are working on a project using Django what
is out there? Does it do what I need? It is always best to just start looking.&lt;/p&gt;
&lt;p&gt;You may already have reasons for not making an app resuable. In the Pinax
project we have a few of those cases. We have three levels of apps.&lt;/p&gt;
&lt;div class="section" id="external-apps"&gt;
&lt;h4&gt;External apps&lt;/h4&gt;
&lt;p&gt;Third party apps provided by the community. They are &lt;code&gt;svn:external&lt;/code&gt;'ed in
the repository.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="local-apps"&gt;
&lt;h4&gt;Local apps&lt;/h4&gt;
&lt;p&gt;These are apps that we have written to fill a specific feature on our site.
They are ones that can be written with many assumptions but the ideas and
features they imploy can be made reusable in the future.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="project-specific-apps"&gt;
&lt;h4&gt;Project specific apps&lt;/h4&gt;
&lt;p&gt;These are esstenially &amp;quot;core&amp;quot; apps. They live at the project level. Currently,
that is either in the &lt;code&gt;basic_project&lt;/code&gt; or &lt;code&gt;complete_project&lt;/code&gt;. These
have dependancies in such way that can not make them resuable in a generic
sense. They are glue between external and local apps to make up certain
features.&lt;/p&gt;
&lt;p&gt;This is ultimately going to be a decision you will need to make. I want to
clarify that a resuable app does not mean it is open sourced and freely
available. They are primarily a clean implementation and proper separation
in your Django project.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="make-an-app"&gt;
&lt;h2&gt;Make an app&lt;/h2&gt;
&lt;p&gt;Creating an app in Django is simple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;manage.py startapp appname
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will give you a skeleton app that you then go and code. One thing that is
left to be desired are many of the modules most apps you see have. For
example some apps come with forms that you can use in your views or templates.
Many people get confused on where these things should go. Some argue that
Django provides a horrible starting point. There are many things that should
be there, but isn't. This has been argued for/against in the past. I think the
starting point Django provides you is an excellent balance between giving you
everything under the sun that you might use and nothing at all. I am certainly
open to improving &lt;code&gt;startapp&lt;/code&gt;, but the default behavior is good enough. The
&lt;a class="reference external" href="http://docs.djangoproject.com/en/dev/"&gt;documentation&lt;/a&gt; makes up for the rest. You are reading it right?&lt;/p&gt;
&lt;div class="section" id="models"&gt;
&lt;h3&gt;Models&lt;/h3&gt;
&lt;p&gt;Models are the foundation around accessing your data in your database. Django
will create you a &lt;code&gt;models.py&lt;/code&gt; file for you. This is where models go.&lt;/p&gt;
&lt;p&gt;One thing that some people don't know is models can be seperated out. If you make
a &lt;code&gt;models&lt;/code&gt; module (a &lt;code&gt;models&lt;/code&gt; directory with an &lt;code&gt;__init__.py&lt;/code&gt; in it) you
can create many other Python modules with models that belong to that app. You
must specify the app name in &lt;code&gt;app_label&lt;/code&gt; of the &lt;code&gt;Meta&lt;/code&gt; class in all the
models for this to work. I typically recommend against this. The first reason
is because of the idea behind a resuable app I discussed above. If you have
this many models in one app, you doing something wrong. Another issue is you
begin to have too many interdepent models that end up causing circular imports.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="forms"&gt;
&lt;h3&gt;Forms&lt;/h3&gt;
&lt;p&gt;Forms are commonly placed in a &lt;code&gt;forms.py&lt;/code&gt; module. This includes regular
forms and model forms. Putting model forms in your &lt;code&gt;models.py&lt;/code&gt; is just the
wrong placement. They are just Python classes that could live anywhere
though, but that would defeat the purpose of this article.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="admin-inteface"&gt;
&lt;h3&gt;Admin Inteface&lt;/h3&gt;
&lt;p&gt;The admin interface is not enabled by default. However, many people use it.
It went through a complete refactor during its newforms-admin days. Originally
the only place where you specified the admin bits was in your models. NFA
fixed that by requiring you to put the new &lt;code&gt;ModelAdmin&lt;/code&gt; declarations in an
&lt;code&gt;admin.py&lt;/code&gt; module.&lt;/p&gt;
&lt;div class="note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;People who used the newforms-admin branch had to deal with many issues
with the placement of &lt;code&gt;ModelAdmin&lt;/code&gt; classes. It mostly came down to
where the &lt;code&gt;register&lt;/code&gt; calls were happening.&lt;/p&gt;
&lt;p class="last"&gt;If you are defining &lt;code&gt;ModelAdmin&lt;/code&gt; and making &lt;code&gt;admin.site.register&lt;/code&gt;
calls in your &lt;code&gt;models.py&lt;/code&gt; or even explicitly importing an &lt;code&gt;admin.py&lt;/code&gt;
in the app's &lt;code&gt;__init__.py&lt;/code&gt; stop doing that. Now.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The admin app comes with a handy function that will properly import all of
your &lt;code&gt;admin.py&lt;/code&gt; modules for you. It is called &lt;code&gt;autodiscover&lt;/code&gt;. I have gone
into depth about this in my &lt;a class="reference external" href="http://oebfare.com/blog/2008/jul/20/newforms-admin-migration-and-screencast/"&gt;newforms-admin migration post&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="views"&gt;
&lt;h3&gt;Views&lt;/h3&gt;
&lt;p&gt;Views are what deal with the request once it is routed. Django provides you
with a &lt;code&gt;views.py&lt;/code&gt; module where you have your view functions. One thing to
note is that these are simply callables. What I mean in the general sense is
that you are not tied to using a Python function. One thing that the admin
does is it uses a class that represents many methods (aka views) that deal
with the &lt;code&gt;HttpRequest&lt;/code&gt;. This is commonly refered to as class-based views.
Here is a quick example:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
class MyView(object):
    def __call__(self, request):
        return HttpResponse(self.get_text())

    def get_text(self):
        return &amp;quot;hello world&amp;quot;
&lt;/pre&gt;
&lt;p&gt;The above is a horrible view, but a good example. In a resuable app you can
easily provide overridable behavior for users of the views. There is proposal
going around in the Django world about using this approach for generic views.
I am personally a big +1 to that idea. It really stemmed out of the many use
cases we saw during the newforms-admin period. Views would become their own
classes where they can inherit base functionality and everything is overriable.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="templates"&gt;
&lt;h3&gt;Templates&lt;/h3&gt;
&lt;p&gt;This deserves its own post. I have one in the works about I how feel in this
area and what is acceptable in a reusable app.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="template-tags"&gt;
&lt;h3&gt;Template tags&lt;/h3&gt;
&lt;p&gt;Template tags are awesome. They already have a pretty well established
convention due to the fact its structure is well defined:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
my_super_sweet_app/
    __init__.py
    models.py
    templatetags/
        __init__.py
        my_super_sweet_app_tags.py
&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;my_super_sweet_app/templatetags/my_super_sweet_app_tags.py&lt;/code&gt; is where you
define your template tags. Be it inclusion tags, filters, custom tags, etc...&lt;/p&gt;
&lt;p&gt;One thing that I have not seen addressed well enough is custom template tag
syntax. There is sort of convention, but nothing very well established. Let
me describe how I typically handle this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;{% images_for_object [obj] as [varname] %}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The structure is that you pluralize what the model is. In this case I have an
&lt;code&gt;Image&lt;/code&gt; model and it contains a generic foreign key. This template tag
takes in an object and then builds a new context variable for you containing
the data you are looking for.&lt;/p&gt;
&lt;p&gt;The convention I am trying to establish is that template tags read nicely.
The above tag uses the word 'as' to indicate that the left hand side is going
to be stored in its right hand right. There are other cases where other
keywords can be used to show how a template tag works:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;{% latest_flights 5 for profile.user as flights %}
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the tag above we are grabbing 5 latest flights for a given user and
storing them in the context variable &lt;code&gt;flights&lt;/code&gt;. I am not saying we can make
a good convention around every template tag there is, but certainly I wanted
to bring it up so you too can think about how this might be good in some
places of your own template tags.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="you-are-cleared-for-landing"&gt;
&lt;h2&gt;You are cleared for landing&lt;/h2&gt;
&lt;p&gt;This blog post has been mostly a brain dump of many things I see through out
my apps. I encourage you to implement some of these ideas and take others
opinions into consideration. The Django reusable app ecosystem is going to
continually get stronger. There are a couple of things I have left off this
post only because I am just beginning to learn more about them myself. I will
be certain to post more things about reusable apps in the near future.&lt;/p&gt;
&lt;/div&gt;
</description><pubDate>Tue, 04 Nov 2008 22:04:52 -0600</pubDate><guid isPermaLink="false">http://oebfare.com/blog/2008/nov/04/reusable-app-conventions/</guid><feedburner:origLink>http://oebfare.com/blog/2008/nov/04/reusable-app-conventions/</feedburner:origLink></item><item><title>Writing a custom management command</title><link>http://feedproxy.google.com/~r/oebfare-latest-entries/~3/FPLS5HvhSiE/</link><description>
&lt;p&gt;One of the neat things you can do in Django 1.0 is write custom management
commands. Django gives you an API that you can use to easily write code that
you can execute on the command line. We are familiar with some of the built-in
ones such as &lt;code&gt;syncdb&lt;/code&gt; and &lt;code&gt;runserver&lt;/code&gt;. This post will cover how to create
our own.&lt;/p&gt;
&lt;div class="section" id="background"&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;Today I was tasked with the need to deploy an application in the wild on my
local intranet. It was a stupid simple Django application that basically used
the admin app to browse some data in a MySQL database. All this will eventually
be in a PostgreSQL database running on a nice Django project. However, in the
mean time I needed something quick and working.&lt;/p&gt;
&lt;p&gt;I could use &lt;code&gt;runserver&lt;/code&gt; and daemonize it. Ideally I wanted something that
could handle multiple requests at time because there were cases when a couple
users would be using this heavily at the same time. I turned to the trusty
&lt;a class="reference external" href="http://www.cherrypy.org/browser/trunk/cherrypy/wsgiserver/__init__.py?format=raw"&gt;WSGI server&lt;/a&gt; that &lt;a class="reference external" href="http://www.cherrypy.org/"&gt;CherryPy&lt;/a&gt; provides. It is multi-threaded and super
simple to setup.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="getting-started"&gt;
&lt;h2&gt;Getting started&lt;/h2&gt;
&lt;p&gt;The reason why I want to blog about this is because the Django documentation
on &lt;a class="reference external" href="http://docs.djangoproject.com/en/dev/howto/custom-management-commands/"&gt;management commands&lt;/a&gt; is pretty sparse. It does show you the basics of
where the command must go to be recongized. Inside your app you will want to
have a directory sturcture similiar to this:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
wsgi/
    __init__.py
    models.py
    management/
        __init__.py
        commands/
            ___init__.py
            runwsgi.py
&lt;/pre&gt;
&lt;p&gt;Above is what my app looks like for the command we are going to write. As you
can see there is &lt;code&gt;wsgi/management/commands/runwsgi.py&lt;/code&gt;. This is where your
command code will live.&lt;/p&gt;
&lt;p&gt;Django provides you with some base classes you can dervive your Command from.
All commands ultimately derive from &lt;code&gt;django.core.management.base.BaseCommand&lt;/code&gt;
and in this case ours will be too. However, if you have a specific task there
may be a helper base class to do some work for you.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;code&gt;django.core.management.base.BaseCommand&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;django.core.management.base.AppCommand&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;django.core.management.base.LabelCommand&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;django.core.management.base.NoArgsCommand&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Most of the command that I write extend from either &lt;code&gt;BaseCommand&lt;/code&gt; or
&lt;code&gt;NoArgsCommand&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="writing-the-management-command"&gt;
&lt;h2&gt;Writing the management command&lt;/h2&gt;
&lt;p&gt;Now that we know where to put our command in our app and what the command can
extend from lets actually see something in action. Here is some code to get
you started on something:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.management.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseCommand&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseCommand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c"&gt;# do something interesting here&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The code above in the case of the layout shown before lives in &lt;code&gt;runwsgi.py&lt;/code&gt;.
The name of the file is significant by the fact it is used in how you call
your management command.&lt;/p&gt;
&lt;div class="note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;Your app must be in &lt;code&gt;INSTALLED_APPS&lt;/code&gt; for Django to see the management
command.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This command can be executed by running in the same directory as
&lt;code&gt;manage.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;./manage.py runwsgi
&lt;/pre&gt;&lt;/div&gt;
&lt;div class="section" id="seriously-do-something-interesting"&gt;
&lt;h3&gt;Seriously, do something interesting&lt;/h3&gt;
&lt;p&gt;Ok, lets cut the crap and get down to something useful. We are writing code
for the &lt;code&gt;runwsgi&lt;/code&gt; management command. Lets see some working code here:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.management.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseCommand&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.handlers.wsgi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;WSGIHandler&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;cherrypy.wsgiserver&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CherryPyWSGIServer&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;ImportError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;wsgiserver&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CherryPyWSGIServer&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseCommand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CherryPyWSGIServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;127.0.0.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;9001&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;WSGIHandler&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Oops. I did say CherryPy's WSGI server was simple right? The above code hooks
up Django right into the CherryPy multi-threaded WSGI server and runs it.
One thing that is interesting, is based on that code, we can see so many
places where we can let the user override values and behavior of the process.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="accepting-and-using-user-options"&gt;
&lt;h3&gt;Accepting and using user options&lt;/h3&gt;
&lt;p&gt;One thing that I find the best part of how Django's management command are
implemented is it provides you with a nice way of specifying options. These
options will come in through the command line that can adjust values based
on how the user wants the process to behave. Based on the code shown just
earlier we can see that we might want to the user to provide the host, port
and specify the ability to daemonize itself. Lets go ahead and add these
options that the user can specify:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.management.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseCommand&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.handlers.wsgi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;WSGIHandler&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;optparse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OptionParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;make_option&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;cherrypy.wsgiserver&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CherryPyWSGIServer&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;ImportError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;wsgiserver&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CherryPyWSGIServer&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseCommand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;option_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BaseCommand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;option_list&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;make_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-h&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;--host&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;host&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;127.0.0.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;make_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-p&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;--port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;9001&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;make_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;--daemon&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;daemonize&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;store_true&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CherryPyWSGIServer&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;host&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="n"&gt;WSGIHandler&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Django provides a quick a simple way to use Python's &lt;code&gt;optparse&lt;/code&gt; &lt;a class="reference external" href="http://www.python.org/doc/2.5.2/lib/module-optparse.html"&gt;module&lt;/a&gt; to
define how you want your command to accept options. We have added options for
host, port and daemonize. I have hooked up the host and port when we create
the &lt;code&gt;CherryPyWSGIServer&lt;/code&gt;. I will touch on daemonize later.&lt;/p&gt;
&lt;p&gt;One thing I want to draw some attension to is specifically the &lt;code&gt;-h&lt;/code&gt; option.
&lt;code&gt;optparse&lt;/code&gt; defines &lt;code&gt;-h&lt;/code&gt; for help. If you try to run the above code you
will get an exception indicating there is a clash. To fix this you need take
control of how Django create the option parser:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.management.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseCommand&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;optparse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OptionParser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;make_option&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseCommand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c"&gt;# ...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subcommand&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;        Create and return the ``OptionParser`` which will be used to&lt;/span&gt;
&lt;span class="sd"&gt;        parse the arguments to this command.&lt;/span&gt;
&lt;span class="sd"&gt;        &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OptionParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;prog_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subcommand&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_version&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;option_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;option_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;conflict_handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;resolve&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The part of significance above is that we are passing in &lt;code&gt;conflict_handler&lt;/code&gt;
to &lt;code&gt;OptionParser&lt;/code&gt;. This lets the parser handle the collision intelligently.
You can read about this on Python documentation for
&lt;a class="reference external" href="http://www.python.org/doc/2.5.2/lib/optparse-conflicts-between-options.html"&gt;conflicts between options&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="daemonizing-the-process"&gt;
&lt;h4&gt;Daemonizing the process&lt;/h4&gt;
&lt;p&gt;One small thing I want to touch on is how you can daemonize this Python
process. Right now it will be attached to the shell and wont be very useful
for long periods of time. I have spent some time with Twisted so I came
across this neat snippet of code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;daemonize&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;    Detach from the terminal and continue as a daemon.&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="c"&gt;# swiped from twisted/scripts/twistd.py&lt;/span&gt;
    &lt;span class="c"&gt;# See http://www.erlenstar.demon.co.uk/unix/faq_toc.html#TOC16&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;   &lt;span class="c"&gt;# launch child and...&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# kill off parent&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setsid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;   &lt;span class="c"&gt;# launch child and...&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# kill off parent again.&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;umask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;077&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/dev/null&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;O_RDWR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dup2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errno&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;errno&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EBADF&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Just put that in your &lt;code&gt;runwsgi.py&lt;/code&gt; file and call it when you need it. You
can do this conditionally based on the option being passed it as well. I will
leave that bit as an exercise to you.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="coming-to-an-end"&gt;
&lt;h2&gt;Coming to an end&lt;/h2&gt;
&lt;p&gt;I have pretty much covered everything I did to write this management command.
It was really simple and we got some usable code out of it. I did leave you
with an exercise if you did want to implement this command, but I like pulling
code from others just as much as you probably do it is available on my blog's
source code. You can find it &lt;a class="reference external" href="http://github.com/brosner/oebfare/tree/b5918c8fc2b01ac72e592205ec8450a44b468d84/apps/wsgi/management/commands/runwsgi.py"&gt;here&lt;/a&gt;. Please ask questions or provide better
examples if you so wish. I would love to hear your opinions and see your code.&lt;/p&gt;
&lt;/div&gt;
</description><pubDate>Mon, 03 Nov 2008 15:42:25 -0600</pubDate><guid isPermaLink="false">http://oebfare.com/blog/2008/nov/03/writing-custom-management-command/</guid><feedburner:origLink>http://oebfare.com/blog/2008/nov/03/writing-custom-management-command/</feedburner:origLink></item><item><title>Standalone Django App Testing</title><link>http://feedproxy.google.com/~r/oebfare-latest-entries/~3/Bebn9CNeOTU/</link><description>
&lt;p&gt;Yesterday I found myself hacking on a Django app. I am working on reviving
my old &lt;a class="reference external" href="http://code.google.com/p/django-categories/"&gt;django-categories&lt;/a&gt; app. More about that later. One thing I came
across pretty quickly was the need to test the app. I had written tests
way back when and wanted to ensure my new code worked with the API users were
expecting. That is if there are actually any users, but mostly because this is
the API I am wanting.&lt;/p&gt;
&lt;p&gt;To test the app I basically needed a &lt;code&gt;settings.py&lt;/code&gt;. I have a simple one
living on my &lt;code&gt;PYTHONPATH&lt;/code&gt; that I use regularly for running the Django test
suite. However, it is not sufficient enough. It simply sets the
&lt;code&gt;DATABASE_ENGINE&lt;/code&gt; and &lt;code&gt;ROOT_URLCONF&lt;/code&gt; settings. The latter setting is a
requirement by Django. The requirement for running these tests involves having
the app in &lt;code&gt;INSTALLED_APPS&lt;/code&gt; which would defeat the purpose of the simple
settings for running the test suite. I needed something to be a bit more
robust.&lt;/p&gt;
&lt;div class="section" id="solving-the-problem"&gt;
&lt;h2&gt;Solving the problem&lt;/h2&gt;
&lt;p&gt;I was talking to &lt;a class="reference external" href="http://ericholscher.com/"&gt;Eric Holscher&lt;/a&gt; on IRC and I came up with the idea of having
a standalone script that allowed some settings values to be passed in over
the command line. The goal was to test the app. You can point it to the app
and it will setup sys.path and &lt;code&gt;INSTALLED_APPS&lt;/code&gt; for you. To point it at the
app you would provide a path to the app:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;app_test_runner.py /path/to/my/app
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is nice because you don't have to make sure the app lives on the
&lt;code&gt;PYTHONPATH&lt;/code&gt; allowing for quick testing. What you do need to ensure is that
any dependancies the app has lives on the &lt;code&gt;PYTHONPATH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The other bit that is of importance is the ability to easily change some
common Django settings. You can easily change the database settings right
over the command line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;app_test_runner.py --DATABASE_ENGINE=postgresql_psycopg2 \
    --DATABASE_NAME=dbname \
    --DATABASE_USER=joe \
    --DATABASE_PASSWORD=password \
    /path/to/my/app
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pretty simple!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="give-me-some-code"&gt;
&lt;h2&gt;Give me some code&lt;/h2&gt;
&lt;p&gt;The code is &lt;a class="reference external" href="http://github.com/brosner/django-app-test-runner/tree/master"&gt;available on GitHub&lt;/a&gt;. I did this so that it can continue to get
better. The only thing I ask of future contributors is that it stays super
simple. The script is pretty small so I would like to paste it here for
convenience:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;optparse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OptionParser&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.conf&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.core.management&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;call_command&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;    The entry point for the script. This script is fairly basic. Here is a&lt;/span&gt;
&lt;span class="sd"&gt;    quick example of how to use it::&lt;/span&gt;

&lt;span class="sd"&gt;        app_test_runner.py [path-to-app]&lt;/span&gt;

&lt;span class="sd"&gt;    You must have Django on the PYTHONPATH prior to running this script. This&lt;/span&gt;
&lt;span class="sd"&gt;    script basically will bootstrap a Django environment for you.&lt;/span&gt;

&lt;span class="sd"&gt;    By default this script with use SQLite and an in-memory database. If you&lt;/span&gt;
&lt;span class="sd"&gt;    are using Python 2.5 it will just work out of the box for you.&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OptionParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--DATABASE_ENGINE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DATABASE_ENGINE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;sqlite3&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--DATABASE_NAME&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DATABASE_NAME&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--DATABASE_USER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DATABASE_USER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--DATABASE_PASSWORD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DATABASE_PASSWORD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--SITE_ID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SITE_ID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;int&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;# check for app in args&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;app_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;IndexError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;You did not provide an app path.&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;SystemExit&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;app_path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;app_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_path&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;parent_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;DATABASE_ENGINE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATABASE_ENGINE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;DATABASE_NAME&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATABASE_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;DATABASE_USER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATABASE_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;DATABASE_PASSWORD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DATABASE_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;SITE_ID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SITE_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;ROOT_URLCONF&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;TEMPLATE_LOADERS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;&amp;quot;django.template.loaders.filesystem.load_template_source&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;&amp;quot;django.template.loaders.app_directories.load_template_source&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;TEMPLATE_DIRS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;templates&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;&amp;quot;INSTALLED_APPS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="c"&gt;# HACK: the admin app should *not* be required. Need to spend some&lt;/span&gt;
            &lt;span class="c"&gt;# time looking into this. Django #8523 has a patch for this issue,&lt;/span&gt;
            &lt;span class="c"&gt;# but was wrongly attached to that ticket. It should have its own&lt;/span&gt;
            &lt;span class="c"&gt;# ticket.&lt;/span&gt;
            &lt;span class="s"&gt;&amp;quot;django.contrib.admin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;&amp;quot;django.contrib.auth&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;&amp;quot;django.contrib.contenttypes&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;&amp;quot;django.contrib.sessions&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;&amp;quot;django.contrib.sites&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;call_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="known-issues"&gt;
&lt;h2&gt;Known issues&lt;/h2&gt;
&lt;p&gt;One issue I came across while working on this bit of code was likely a bug
in Django. In Django there is a unit test called &lt;code&gt;ChangePasswordTest&lt;/code&gt; that
uses &lt;code&gt;setUp&lt;/code&gt; and &lt;code&gt;tearDown&lt;/code&gt; to setup the &lt;code&gt;TEMPLATE_DIRS&lt;/code&gt; to get the
&lt;code&gt;login.html&lt;/code&gt; template. Well, this overrides the whole &lt;code&gt;TEMPLATE_DIRS&lt;/code&gt; and
doesn't allow user defined values there. This creates a case where when
&lt;code&gt;django.contrib.admin&lt;/code&gt; is not in &lt;code&gt;INSTALLED_APPS&lt;/code&gt; you will get test
failures. I haven't had a terrible amount of time to look into this. I have
temporarily patched this by including the &lt;code&gt;admin&lt;/code&gt; app in &lt;code&gt;INSTALLED_APPS&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
</description><pubDate>Sun, 02 Nov 2008 14:46:38 -0600</pubDate><guid isPermaLink="false">http://oebfare.com/blog/2008/nov/02/standalone-django-app-testing/</guid><feedburner:origLink>http://oebfare.com/blog/2008/nov/02/standalone-django-app-testing/</feedburner:origLink></item></channel></rss>
