<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>t+1 &#187; Python</title>
	<atom:link href="http://blog.tplus1.com/index.php/category/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.tplus1.com</link>
	<description>Programming, gardening, economics, life in Cleveland Heights</description>
	<lastBuildDate>Sat, 07 Jan 2012 21:12:21 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Notes from Cleveland code retreat</title>
		<link>http://blog.tplus1.com/index.php/2011/01/18/notes-from-cleveland-code-retreat/</link>
		<comments>http://blog.tplus1.com/index.php/2011/01/18/notes-from-cleveland-code-retreat/#comments</comments>
		<pubDate>Wed, 19 Jan 2011 02:49:02 +0000</pubDate>
		<dc:creator>matt</dc:creator>
				<category><![CDATA[Cleveland Life]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.tplus1.com/?p=697</guid>
		<description><![CDATA[I attended the day-long Code Retreat at Lean Dog&#8217;s floating office on Sunday.
We worked in pairs for 45-minute blocks of time, building Conway&#8217;s Game of Life.  In each session, we started from the beginning.  We didn&#8217;t build on previous code.
After each session, teams talked about what stuff they discovered.  Then we reorganized [...]]]></description>
			<content:encoded><![CDATA[<p>I attended the day-long Code Retreat at Lean Dog&#8217;s floating office on Sunday.</p>
<p>We worked in pairs for 45-minute blocks of time, building Conway&#8217;s Game of Life.  In each session, we started from the beginning.  We didn&#8217;t build on previous code.</p>
<p>After each session, teams talked about what stuff they discovered.  Then we reorganized into new pairs and started working from the beginning again.</p>
<h2>First pairing</h2>
<p>At first I paired with a C# developer.  While other teams went right into writing test programs, we spent a fair amount of time talking and sketching out ideas about how to model the game.</p>
<p>Then we made a grid that knew how to generate the next state just by copying itself into a new grid.</p>
<p>We planned to add in code to support each of the four rules of the game of life one by one.</p>
<p>So, we wrote a test that created a grid with just a single living cell.  Then we told that grid to make a grid for the next generation, and our test verified that the single cell survived the copy.</p>
<p>Then we started working on the first rule: if a cell is alive and has less than two neighbors, it dies.</p>
<p>We burned through the reminder of time sketching out ideas on my clipboard.  By the end of our time, it was clear that we only needed to pay attention to living cells and neighbors of living cells.</p>
<p>It was also clear that the time spent writing the first test and then writing the code to satisfy the first test did nothing to move us toward a real solution.</p>
<h2>Second pairing</h2>
<p>Next I worked with a Java guy.  This time, we did something a little closer to TDD.</p>
<p>We decided to start from the point of view of an end-user firing up the game.  The user would want to make a grid, add a few living cells, and then tell the grid to generate its next state.</p>
<p>The first code we wrote was a test and we started writing tests almost immediately.  In the test, we instantiated a Grid class.  That test blew up with an error, since no Grid class existed.  So then we wrote a grid class.  It had no methods or attributes, but that was all we needed to write in order to satisfy our test.</p>
<p>Next we wrote a new test that instantiated a grid and then added a single cell by calling an (undefined) addCell(&#8230;) method.</p>
<p>After seeing that test crash with an error, we wrote an addCell(&#8230;) method that was a no-op, because that&#8217;s all our tests required us to do.</p>
<p>Then we wrote a test for rule one, where a living cell with less than two neighbors dies.</p>
<p>In this test, we made a grid, added a single cell, and then told the grid to create a new grid that represented itself in the future.  Then we used an assert to verify the new grid had no cells.</p>
<p>First we added a &#8220;cells&#8221; instance-level ListArray attribute to our grid class.  Then we wrote a generate_next_grid method on our grid class, and all that did was instantiate and return a new grid with an empty cells. </p>
<p>And bingo, we had enough code again to pass our test.</p>
<p>At this point, I became convinced that the kind of testing we were doing was harming our productivity.  We had fallen into some kind of xeno&#8217;s paradox<a href="#xeno">*</a> where we would never actually get anything done, because we could always think of some new test that applied to a trivial subset of the project, and then work on writing code to satisfy that test.</p>
<blockquote><p>
<a name="xeno">*</a>A dude shoots an arrow at a target.  Before the arrow gets to the target, it has to cross half the distance to the target.  Then it     can cross the other half of the distance.  But now it has to cross half of the remaining distance, so it does that.</p>
<p>    Then it has to cross half of that remaining distance, and then half of the remaining distance after that, and so on for infinity.</p>
<p>    Since the arrow has an infinite number of partial distances to cross, the arrow will never reach the target.</p>
<p>    Read more about it <a href="http://en.wikipedia.org/wiki/Zeno's_paradoxes#The_dichotomy_paradox">here</a>.
</p></blockquote>
<p>I was itching to solve a real problem, rather than just watch lights blink from red to green, so I cajoled my partner into writing a test for the <a href="http://en.wikipedia.org/wiki/Conway's_Game_of_Life#Examples_of_patterns">blinker pattern</a>, which is when a 3&#215;1 rectangle of cells converts to a 1&#215;3 rectangle of cells on the second turn, and then on the third turn, converts back to a 3&#215;1 rectangle.</p>
<p>So, we started talking about how to implement the rules.  We decided we needed to figure out for every cell that was near a living cell, how many living neighbors it had.  So we wrote a method to generate the coordinates for the eight neighboring cell to a particular cell, and wrote a test for that.</p>
<p>Then we were going to make a neighbor_count hashmap attribute on our grid and we were going to use that to link cells to how many neighbors each had, and then the time ran out.</p>
<p>At this point, I had a good feeling about the algorithms involved in solving this project.</p>
<h2>Third pairing</h2>
<p>Right before the third pairing, a much older fellow raised his hand and asked if anyone wanted to work together on a solution that only tracked the living cells.  That&#8217;s the approach I was using, so I paired with this guy.  He said he didn&#8217;t care what language we used, but he was a lousy typist.  So I said I could do the typing and we could use python.</p>
<p>At first we excitedly talked over each other and drew pictures until we confirmed we had the same solution in mind.  It turned out my partner was an old common lisp hacker, and once he realized that I understood what he meant when he talked about stuff like &#038;rest and cadr, we got along really well.</p>
<p>The first bit of code I wrote was a cell class with an x and a y attribute, and a method to generate a list of eight nearby cells.</p>
<p>I wrote a quick test in the same file as my code for that to make sure the execution was correct.</p>
<p>Of course, that test failed.  I had lots of syntax errors because I was writing so fast and defending against good-natured jabs about how vim was so vastly inferior to emacs.</p>
<p>After a few cycles of fixing typos and rerunning the tests, we got the syntax errors out of the code.  Then we attacked the project of generating the next state of the grid.</p>
<p>I had already seen how easy it was to write a test for the blinker pattern, so I wrote a quick test for that.  The test made a grid with three cells in a vertical rectangle, then told the grid to generate the next state, then it tested that in the next state, the three cells were in a horizontal rectangle.</p>
<p>We wrote a grid class with a dictionary attribute of living cells in the current generation and a dictionary attribute of cells that would live in the next generation.</p>
<p>Then we wrote the function in our grid class to generate another grid.  The function did an outer loop on all the living cells, then for each living cell, it looped through all the neighbors of that living cell, and then did an inner loop of all neighbors of that neighbor, and then counted up how many were alive.</p>
<p>Then we implemented the four rules of the game with two if-clauses.</p>
<p>We ran the test again, and of course, the code was again littered with indentation errors and mismatched parentheses because of how fast I had been typing and moving stuff around.</p>
<p>Then the timer went off.  I stayed put while everybody was gathering in the middle to talk about how everything went.  Within about 30 seconds I got the last few silly typing glitches fixed, and BAM.  The test passed.</p>
<p>I walked over to my partner and told him we solved it.</p>
<p>Then we listened to other teams talk.  The conversation centered around naming conventions that people were coming up with, like &#8220;sustainable neighborhood&#8221; and &#8220;four horsemen&#8221;.</p>
<p>I raised my hand and asked if anybody had written tests for any of the patterns in game of life beyond the blinker pattern, like tests for the glider pattern, or any of the other patterns shown on the wikipedia page.</p>
<p>Nobody replied to that.  Instead the conversation shifted to a discussion of whether or not booleans hidden behind getters and setters were a sign of a bad design.</p>
<p>I think it was while somebody was talking about writing tests for their (nonexistent) display code that my partner leaned over and said &#8220;This is a <a href="http://en.wikipedia.org/wiki/Drunkard's_search">drunkard&#8217;s search</a>.&#8221; Of course, I didn&#8217;t know what meant, so he explained it.  Here&#8217;s the wikipedia entry:</p>
<blockquote><p>
Conducting a drunkard&#8217;s search is to look in the place that&#8217;s easiest, rather than in the place most likely to yield results.  Taken from an old joke about a drunkard who loses his car keys while unlocking his car and is found looking under a streetlamp down the road because the light is better, it has been an object of consideration in the social sciences since at least 1964.
</p></blockquote>
<h2>Fourth pairing</h2>
<p>I asked if anybody wanted to see a python solution, and four of us worked together, with me doing the typing.</p>
<p>First I described how we would need to find the eight neighboring cells of a particular cell.  So I wrote a test for that, and then wrote the code to satisfy that test.</p>
<p>Then once that was finished, I described what the blinker looked like, and I wrote a test for that.</p>
<p>Then I reused the approach that we came up with in the third pairing, and then got it working fairly quickly.</p>
<p>At one point I showed the code we had written to one of the people running the event, and he pointed out two things (this is roughly paraphrased, and I hope I am getting these ideas correct):</p>
<ol>
<li>I had four if-clauses in a single function, and each if-clause tested two independent variables.  So that means there were dozens of paths through the function that would have to be tested.</li>
<li>My blinker test could be satisfied by code that just hardcoded the expected results, rather than built an actual game-of-life system.  My test didn&#8217;t force a complete solution.</li>
</ol>
<p>Both points illustrate the biggest difference in the TDD mindset versus whatever it is called that I do.  (design by intuition?)  </p>
<p>The fact that I didn&#8217;t have a test for every path that I created didn&#8217;t really concern me, because I was focused on getting the blinker pattern to work.  If that blinker pattern test failed, then I might go in to my code and make sure that what I wrote was really what I meant, or maybe I&#8217;d even throw it all out and start from scratch.  But I wouldn&#8217;t worry about covering all corners of this version until I was confident I was on the right track.</p>
<p>As for the second point, I use tests to catch errors, not to tell me what to write.  I wouldn&#8217;t write code that returns a hard-coded list of values just to pass a test, unless I actually thought I could solve the real problem by doing that.</p>
<p>Anyhow, we got everything working pretty quickly this second time.  You can see the output from my fourth pairing <a href="https://gist.github.com/782350">here</a>.</p>
<p>After you download that code, you can run the tests like this:<br />
<pre><code>
&nbsp;&nbsp;&nbsp;&nbsp;$ python life.py
&nbsp;&nbsp;&nbsp;&nbsp;..
&nbsp;&nbsp;&nbsp;&nbsp;--------------------------------------------------------------------
&nbsp;&nbsp;&nbsp;&nbsp;Ran 2 tests in 0.001s

&nbsp;&nbsp;&nbsp;&nbsp;OK
</code></pre><br />
Those two dots mean that my two tests passed.  I spent the remainder of the time showing how to use the interactive interpreter and how to write doctests.  I&#8217;ve tested a few of the patterns from the wikipedia page, and my code seems to do the right thing, but I&#8217;m not absolutely convinced that this implementation is correct.</p>
<h2>Fifth pairing</h2>
<p>I worked with two guys and we used ruby and rspec.  I described the algorithm that I had used in the last two times, and we decided to work on building that.</p>
<p>We went with the approach of not writing any more code than was required to satisfy the tests.</p>
<p>So, first, we wrote some tests to instantiate a cell class, then we wrote some tests to call a neighbors method on the cell class and verify that it return a list of eight things, and then we verified that the first and last and elements in the neighbors list were at the position that we expected them to be at.</p>
<p>Then we started work on the grid class.  We wanted to make sure that two different objects with the same values for their x and y attributes would be considered equal.  But none of us knew how to redefine the == operator in ruby, and while we were researching this, the time ran out.</p>
<p>Again, I felt like we had fallen into the trap of slicing off trivial subsets of the real problem, and solving them, rather than attacking the real problem.</p>
<h2>Commentary</h2>
<p>Writing tests to check for errors (which is what I do) is not test-driven development.  I daydream about solutions until I find one that I like, and then I build it, and I see if it works by writing tests to cover all the use cases I can think of.</p>
<p>My design comes from idle thoughts and doodles on my notepad, not from the testing.</p>
<p>Final note: I&#8217;ve tried my best to keep any generalizations and extrapolations out of this post.  I don&#8217;t mean for this to be seen as an attack on anyone&#8217;s style of work.  I&#8217;m very, very grateful for everything I&#8217;ve learned about how to write tests for software from the TDD community.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tplus1.com/index.php/2011/01/18/notes-from-cleveland-code-retreat/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>how to restart a gunicorn server without leaving vim</title>
		<link>http://blog.tplus1.com/index.php/2010/12/31/how-to-restart-a-gunicorn-server-from-vim/</link>
		<comments>http://blog.tplus1.com/index.php/2010/12/31/how-to-restart-a-gunicorn-server-from-vim/#comments</comments>
		<pubDate>Sat, 01 Jan 2011 01:43:39 +0000</pubDate>
		<dc:creator>matt</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://blog.tplus1.com/?p=684</guid>
		<description><![CDATA[I&#8217;ve been using the gunicorn WSGI server lately while I work on my next project.  gunicorn is fantastic, except for one tiny nuisance.  I have to restart gunicorn as I change my app code.  At the beginning, this meant I would switch over to the terminal where gunicorn was running.  Then [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been using the <a href="http://gunicorn.org">gunicorn WSGI server</a> lately while I work on my next project.  gunicorn is fantastic, except for one tiny nuisance.  I have to restart gunicorn as I change my app code.  At the beginning, this meant I would switch over to the terminal where gunicorn was running.  Then I&#8217;d kill the parent process by hitting CTRL+C, and then start it up again, by typing:</p>
<p><code>gunicorn crazyproject.webapp:make_application</code></p>
<p>Other frameworks often have a development mode that forks off a helper process that watches the source code folder.  When some file changes, the helper tells the server to reload.</p>
<p>I&#8217;m not using any frameworks this time, so I don&#8217;t have that feature.  I never really liked the fact that every time I saved a file, I would restart the server during development.  Instead, in this case, I want to easily restart gunicorn, but only when I want to, and I don&#8217;t want to leave my editor.</p>
<p>It turned out to be pretty easy to do.</p>
<p>First I read in the <a href="http://gunicorn.org/faq.html">excellent gunicorn docs</a> how to tell gunicorn to reload my app:</p>
<blockquote><p>
How do I reload my application in Gunicorn?</p>
<p>You can gracefully reload by sending HUP signal to gunicorn:</p>
<p><code>$ kill -HUP masterpid</code>
</p></blockquote>
<p>Next I added a &#8211;pid /tmp/gunicorn.pid option to the command that I use to start gunicorn, so that gunicorn would write the parent&#8217;s process ID into /tmp/gunicorn.pid.</p>
<p>Now any time I want gunicorn to reload, I can do this little command in a terminal window:</p>
<p><code>$ kill -HUP `cat /tmp/gunicorn.pid`</code></p>
<p>Those backticks around cat /tmp/gunicorn.pid tell the shell to do that part of the command first, and then feed the result into the rest of the command.</p>
<p>You can always use ! in vim to run some command-line program.  If I had to explain the difference between vim and emacs, the one difference that is most interesting to me is that vim makes it super-easy to send buffer contents to other programs or read buffer contents from other programs, while the people behind emacs seem to think that any external dependency should ultimately be moved into emacs itself.  I get the feeling that vim wants to be my text editor, but emacs wants to be my OS.</p>
<p>Anyhow, while I&#8217;m in vim, I run that command to restart like this:</p>
<p><code>: !kill -HUP `cat /tmp/gunicorn.pid`</code></p>
<p>After using that code for a while, and feeling confident it worked right, I mapped F12 in vim to do that action for me by adding this little thing to the end of my ~/.vimrc:</p>
<p><code>:map &lt;F12&gt; :!kill -HUP `cat /tmp/gunicorn.pid`&lt;CR&gt;</code></p>
<p>Now that means I hit F12 when I want to reload gunicorn.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tplus1.com/index.php/2010/12/31/how-to-restart-a-gunicorn-server-from-vim/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Looking for a few CLE pythoners for a quick project</title>
		<link>http://blog.tplus1.com/index.php/2010/11/02/looking-for-a-few-cle-pythoners-for-a-quick-project/</link>
		<comments>http://blog.tplus1.com/index.php/2010/11/02/looking-for-a-few-cle-pythoners-for-a-quick-project/#comments</comments>
		<pubDate>Tue, 02 Nov 2010 23:19:34 +0000</pubDate>
		<dc:creator>matt</dc:creator>
				<category><![CDATA[Cleveland Life]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[startup life]]></category>

		<guid isPermaLink="false">http://blog.tplus1.com/?p=666</guid>
		<description><![CDATA[I can build it myself, but it&#8217;s going to take a lot longer.  I&#8217;m looking for a few people to help me build a geographical search app.
If you&#8217;re smart, live near me, and have at least eight hours a week to work, let me know.
This will be for some combination of money up front [...]]]></description>
			<content:encoded><![CDATA[<p>I can build it myself, but it&#8217;s going to take a lot longer.  I&#8217;m looking for a few people to help me build a geographical search app.</p>
<p>If you&#8217;re smart, live near me, and have at least eight hours a week to work, let me know.</p>
<p>This will be for some combination of money up front and equity.</p>
<p>I expect to launch in anywhere from six weeks to three months after the start.</p>
<p>I have no patience for ideologues, jackanapes, or freeloaders.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tplus1.com/index.php/2010/11/02/looking-for-a-few-cle-pythoners-for-a-quick-project/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A new pitz release (1.1.2)</title>
		<link>http://blog.tplus1.com/index.php/2010/10/04/a-new-pitz-release-1-1-2/</link>
		<comments>http://blog.tplus1.com/index.php/2010/10/04/a-new-pitz-release-1-1-2/#comments</comments>
		<pubDate>Tue, 05 Oct 2010 03:20:43 +0000</pubDate>
		<dc:creator>matt</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[pitz]]></category>

		<guid isPermaLink="false">http://blog.tplus1.com/?p=647</guid>
		<description><![CDATA[I&#8217;m using semantic versioning now, so I bumped from 1.0.7 to 1.1.0 after adding a few tweaks to the command-line interface.  Then I discovered a silly mistake in the setup.py file, and released 1.1.1.  Then I realized I did the fix wrong, and then released 1.1.2 a few minutes later.
The &#8211;quick option
Normally, running [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m using <a href="http://semver.org">semantic versioning</a> now, so I bumped from 1.0.7 to 1.1.0 after adding a few tweaks to the command-line interface.  Then I discovered a silly mistake in the setup.py file, and released 1.1.1.  Then I realized I did the fix wrong, and then released 1.1.2 a few minutes later.</p>
<h2>The &#8211;quick option</h2>
<p>Normally, running <b><code>pitz-add-task</code></b> will prompt for a title and then open $EDITOR so I can write a description.  After that, pitz will ask for choices for milestone, owner, status, estimate, and tags.</p>
<p>Sometimes I want to make a quick task without getting prompted for all this stuff.</p>
<p>I already had a <b><code>--no-description</code></b> option that would tell <b><code>pitz-add-task</code></b> to not open $EDITOR for a description.  And I already had a <b><code>--use-defaults</code></b> option to just choose the default values for milestone, owner, status, estimate, and tags.</p>
<p>But when I just want to make a quick to-do task as a placeholder, writing out all this stuff:<pre><code>$ pitz-add-task --no-description --use-defaults -t &quot;Fix fibityfoo&quot;
</code></pre></p>
<p>is kind of a drag.  So I made a <b><code>--quick</code></b> option (also available as <b><code>-q</code></b>) that does the same thing as <b><code>--no-description --use-defaults</code></b>.</p>
<h2>The -1 alias for &#8211;one-line-view</h2>
<p>This is the typical way that a to-do list looks:<pre><code>$ pitz-my-todo -n 3
==============================
slice from To-do list for matt
==============================

(3 task entities, ordered by [&#039;milestone&#039;, &#039;status&#039;, &#039;pscore&#039;])

Write new CLI scripts (witz!) to talk to pitz-webapp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9f1c76
matt | paused | difficult | 1.0 | 1
webapp, CLI
Starting up and loading all the pitz data at the beginning of ever...

Experiment with different task summarized views&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0f6fee
matt | unstarted | straightforward | 1.0 | 1
CLI
Right now, the summarized view of a task looks a little like this:...

Add more supported URLs to pitz-webapp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 295b5f
matt | unstarted | straightforward | 1.0 | 0
webapp
I want to allow these actions through the webapp:&nbsp;&nbsp;*&nbsp;&nbsp; Insert a ne...
</code></pre></p>
<p>Incidentally, notice the <b><code>-n 3</code></b> option limits the output to the first three tasks.</p>
<p>Tasks also have a one-line view:<pre><code>$ pitz-my-todo -n 3 --one-line-view
==============================
slice from To-do list for matt
==============================

(3 task entities, ordered by [&#039;milestone&#039;, &#039;status&#039;, &#039;pscore&#039;])

Write new CLI scripts (witz!) to talk to pitz-webapp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9f1c76
Experiment with different task summarized views&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0f6fee
Add more supported URLs to pitz-webapp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 295b5f
</code></pre></p>
<p>Typing out <b><code>--one-line-view</code></b> is tedious, so now, <b><code>-1</code></b> is an alias that works as well:<pre><code>$ pitz-my-todo -n 3 -1
==============================
slice from To-do list for matt
==============================

(3 task entities, ordered by [&#039;milestone&#039;, &#039;status&#039;, &#039;pscore&#039;])

Write new CLI scripts (witz!) to talk to pitz-webapp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9f1c76
Experiment with different task summarized views&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0f6fee
Add more supported URLs to pitz-webapp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 295b5f
</code></pre></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tplus1.com/index.php/2010/10/04/a-new-pitz-release-1-1-2/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Build your own kind of dictionary</title>
		<link>http://blog.tplus1.com/index.php/2010/08/13/build-your-own-kind-of-dictionary/</link>
		<comments>http://blog.tplus1.com/index.php/2010/08/13/build-your-own-kind-of-dictionary/#comments</comments>
		<pubDate>Fri, 13 Aug 2010 13:10:57 +0000</pubDate>
		<dc:creator>matt</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.tplus1.com/?p=624</guid>
		<description><![CDATA[This is the video from my PyOhio talk on building objects that can act like dictionaries.

The text and programs from my talk on building your own are available here on github.  You can probably absorb the information most quickly by reading the talk.rst file.
Please let me know if you find spelling errors or goofy [...]]]></description>
			<content:encoded><![CDATA[<p>This is the video from my <a href="http://pyohio.org">PyOhio</a> talk on building objects that can act like dictionaries.</p>
<p><embed src="http://blip.tv/play/AYH0yjwC" type="application/x-shockwave-flash" width="480" height="350" allowscriptaccess="always" allowfullscreen="true"></embed></p>
<p>The text and programs from my talk on building your own are available <a href="http://github.com/mw44118/your-own-kind-of-dictionary">here</a> on github.  You can probably absorb the information most quickly by reading <a href="http://github.com/mw44118/your-own-kind-of-dictionary/blob/master/pyohio/talk.rst">the talk.rst file</a>.</p>
<p>Please let me know if you find spelling errors or goofy sentences that are hard to understand that I should rewrite.</p>
<p>This is the description for the talk:</p>
<blockquote><p>
My talk is based on a project that seemed very simple at first. I wanted an object like the regular python dictionary, but with a few small tweaks:</p>
<ul>
<li>values for some keys should be restricted to elements of a set</li>
<li>values for some keys should be restricted to instances of a type</li>
</ul>
<p>For example, pretend I want a dictionary called favorites, and I want the value for the &#8220;color&#8221; key to be any instance of my Color class. Meanwhile, for the &#8220;movie&#8221; key, I want to make sure that the value belongs to my set of movies.</p>
<p>In the talk, I&#8217;ll walk through how I used tests to validate my different implementations until I came up with a winner.</p>
<p>Unlike my talk last year on metaclass tomfoolery, and the year before that on fun with decorators (and decorator factories) I&#8217;m hoping to make this talk straightforward and friendly to beginning programmers.</p>
<p>You&#8217;ll see:</p>
<ul>
<li>how I use tests to solve a real-world problem</li>
<li>a few little gotchas with the super keyword</li>
<li>a little about how python works under the hood</li>
</ul>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://blog.tplus1.com/index.php/2010/08/13/build-your-own-kind-of-dictionary/feed/</wfw:commentRss>
		<slash:comments>-1</slash:comments>
		</item>
		<item>
		<title>I just submitted my talk for PyOhio 2010</title>
		<link>http://blog.tplus1.com/index.php/2010/05/09/i-just-submitted-my-talk-for-pyohio-2010/</link>
		<comments>http://blog.tplus1.com/index.php/2010/05/09/i-just-submitted-my-talk-for-pyohio-2010/#comments</comments>
		<pubDate>Sun, 09 May 2010 17:01:44 +0000</pubDate>
		<dc:creator>matt</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[self-aggrandizement]]></category>

		<guid isPermaLink="false">http://blog.tplus1.com/?p=595</guid>
		<description><![CDATA[I&#8217;d be happy to get any crititicism ahead of the presentation.  I&#8217;m hosting the code examples and the talk material here.
Building your own kind of dictionary
Python level: novice
Description
My talk is based on a project that seemed very simple at first.  I wanted an object like the regular python dictionary, but with a few [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;d be happy to get any crititicism ahead of the presentation.  I&#8217;m hosting the code examples and the talk material <a href="http://github.com/mw44118/your-own-kind-of-dictionary">here</a>.</p>
<h2>Building your own kind of dictionary</h2>
<p><em>Python level: novice</em></p>
<h3>Description</h3>
<p>My talk is based on a project that seemed very simple at first.  I wanted an object like the regular python dictionary, but with a few small tweaks:</p>
<ul>
<li>values for some keys should be restricted to elements of a set</li>
<li>values for some keys should be restricted to instances of a type</li>
</ul>
<p>For example, pretend I want a dictionary called favorites, and I want the value for the &#8220;color&#8221; key to be any instance of my Color class.  Meanwhile, for the &#8220;movie&#8221; key, I want to make sure that the value belongs to my set of movies.</p>
<p>In the talk, I&#8217;ll walk through how I used tests to validate my different implementations until I came up with a winner.</p>
<p>Unlike my talk last year on metaclass tomfoolery, and the year before that on fun with decorators (and decorator factories) I&#8217;m hoping to make this talk straightforward and friendly to beginning programmers.</p>
<p>You&#8217;ll see:</p>
<ul>
<li>how I use tests to solve a real-world problem</li>
<li>gotchas with the super keyword</li>
<li>a little about how python works under the hood.</li>
</ul>
<h3>Extended description</h3>
<p>I&#8217;m not done with the slides, but all my code examples are finished.  You can read it all online at my github repository <a href="http://github.com/mw44118/your-own-kind-of-dictionary">here</a>.</p>
<h3>Outline</h3>
<ol>
<li>What kind of object I want
<ol>
<li>Tests define the expected behavior</li>
<li>How to run those tests</li>
</ol>
</li>
<li>First implementation (subclass dict)
<ol>
<li>How the implementation is defined</li>
<li>Examine test results</li>
<li>Examine the C code behind the dict class to see why my subclassed __setitem__ method won&#8217;t get called from the parent class</li>
</ol>
</li>
<li>Composition-based implementation
<ol>
<li>Explain composition vs inheritance</li>
<li>Examine test results</li>
<li>Point out irritating need to manually redefine every related dictionary method on the container class</li>
<li>Show how to use __getattr__ to avoid all that boring wrapper code</li>
<li>Show how __getattr__ doesn&#8217;t play nice with inspection tools</li>
</ol>
</li>
<li>UserDict.UserDict
<ol>
<li>Explain implementation</li>
<li>Examine test results</li>
<li>Add a new test that uses this class as a parent for a subclass</li>
<li>Explain how UserDict.UserDict is not a new-style class, so the super keyword behaves differently</li>
</ol>
</li>
<li>UserDict.DictMixin
<ol>
<li>Explain implementation</li>
<li>Examine test results</li>
</ol>
</li>
<li>PEP 3119 and why it is nice
<ol>
<li>duck-typing, why it is awesome, why it isn&#8217;t perfect</li>
<li>abstract base classes</li>
<li>As of python 2.6, don&#8217;t use UserDict.DictMixin; use collections.MutableMapping</li>
</ol>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://blog.tplus1.com/index.php/2010/05/09/i-just-submitted-my-talk-for-pyohio-2010/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>pitz 1.0.5 now supports bash colorization</title>
		<link>http://blog.tplus1.com/index.php/2010/03/22/pitz-1-0-5-now-supports-bash-colorization/</link>
		<comments>http://blog.tplus1.com/index.php/2010/03/22/pitz-1-0-5-now-supports-bash-colorization/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 21:09:14 +0000</pubDate>
		<dc:creator>matt</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[pitz]]></category>

		<guid isPermaLink="false">http://blog.tplus1.com/?p=572</guid>
		<description><![CDATA[Today is day one of my week off.  The rainy weather kept me inside, so I added a bash coloring to pitz.  The screen shot below shows an example:
It took me a while to figure out how to include the jinja2 template files with the package, but you can now download pitz from [...]]]></description>
			<content:encoded><![CDATA[<p>Today is day one of my week off.  The rainy weather kept me inside, so I added a bash coloring to pitz.  The screen shot below shows an example:</p>
<div id="attachment_571" class="wp-caption alignleft" style="width: 672px"><a href="http://blog.tplus1.com/wp-content/uploads/2010/03/pitz-bash-colorization.png"><img src="http://blog.tplus1.com/wp-content/uploads/2010/03/pitz-bash-colorization.png" alt="screenshot" title="pitz-bash-colorization" width="662" height="435" class="size-full wp-image-571" /></a><p class="wp-caption-text">pretty colors</p></div>
<p>It took me a while to figure out how to include the jinja2 template files with the package, but you can now download pitz from PyPi <a href="http://pypi.python.org/pypi/pitz">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tplus1.com/index.php/2010/03/22/pitz-1-0-5-now-supports-bash-colorization/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>New year&#8217;s python meme</title>
		<link>http://blog.tplus1.com/index.php/2010/01/04/new-years-python-meme/</link>
		<comments>http://blog.tplus1.com/index.php/2010/01/04/new-years-python-meme/#comments</comments>
		<pubDate>Mon, 04 Jan 2010 05:10:10 +0000</pubDate>
		<dc:creator>matt</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.tplus1.com/?p=538</guid>
		<description><![CDATA[Doing this after reading about it on Ben&#8217;s blog.
1. What’s the coolest Python application, framework or library you have discovered in 2009 ?
I love the restructured text tools.  I use rst2pdf at least once a week.
2. What new programming technique did you learn in 2009?
This was a year of giving up on techniques, paradigms, [...]]]></description>
			<content:encoded><![CDATA[<p>Doing this after reading about it on <a href="http://just-another.net/2009/12/28/new-years-python-meme/">Ben&#8217;s blog</a>.</p>
<h2>1. What’s the coolest Python application, framework or library you have discovered in 2009 ?</h2>
<p>I love the restructured text tools.  I use <a href="http://code.google.com/p/rst2pdf/">rst2pdf</a> at least once a week.</p>
<h2>2. What new programming technique did you learn in 2009?</h2>
<p>This was a year of giving up on techniques, paradigms, development methods, frameworks, and fanciness in general and going back to basics.  I&#8217;m like Rocky Balboa in Rocky IV &#8212; jogging in the snow and chopping wood with an axe.</p>
<h2>3. What’s the name of the open source project you contributed the most in 2009? What did you do?</h2>
<p>I&#8217;ve been working on <a href="http://github.com/mw44118/pitz">pitz</a> for about 15 months now.  I&#8217;ve learned about a lot of stuff that I didn&#8217;t expect to learn when I decided to build a to-do manager.  Because of that project, I&#8217;ve learned about how templating systems like jinja2 work internally, how to use cProfile, how to write tests for all sorts of weird situations, how to write a simple querying system, etc.</p>
<h2>4. What was the Python blog or website you read the most in 2009?</h2>
<p>I just went through my bookmarks tagged with python and didn&#8217;t see an obvious pattern.  These days, the hundred or so people I follow on twitter keep me supplied with too much to read.</p>
<h2>5. What are the three top things you want to learn in 2010 ?</h2</p>
<p>psycopg2 internals, datetime module internals (it is written in C and there is a patch I want to submit), and maybe stuff like ast.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tplus1.com/index.php/2010/01/04/new-years-python-meme/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Add an option for your script to drop into the debugger</title>
		<link>http://blog.tplus1.com/index.php/2009/12/24/add-an-option-for-your-script-to-drop-into-the-debugger/</link>
		<comments>http://blog.tplus1.com/index.php/2009/12/24/add-an-option-for-your-script-to-drop-into-the-debugger/#comments</comments>
		<pubDate>Thu, 24 Dec 2009 19:49:04 +0000</pubDate>
		<dc:creator>matt</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.tplus1.com/?p=523</guid>
		<description><![CDATA[I like using the python debugger to, umm, debug stuff.  Just recently I wanted to use pdb to poke around in a script that would intermittently crash.  I wanted to add an option to my script that would drop me into pdb when the script dies.
This turned out to be trivial to write. [...]]]></description>
			<content:encoded><![CDATA[<p>I like using the python debugger to, umm, <strong>debug</strong> stuff.  Just recently I wanted to use pdb to poke around in a script that would intermittently crash.  I wanted to add an option to my script that would drop me into pdb when the script dies.</p>
<p>This turned out to be trivial to write.  The script scratch.py doesn&#8217;t do much, but if you add the <code>--drop-into-debugger</code> option, you&#8217;ll get dumped into a pdb session, where you can study the problem more closely, like this:<pre><code>$ python scratch.py --drop-into-debugger
&gt; /home/matt/scratch.py(15)main()
-&gt; 1/0
(Pdb) 
</code></pre><br />
When I don&#8217;t add the <code>--drop-into-debugger</code> option, then of course the uncaught exception just crashes the script:<pre><code>
$ python scratch.py
Traceback (most recent call last):
&nbsp;&nbsp;File &quot;scratch.py&quot;, line 23, in &lt;module&gt;
&nbsp;&nbsp;&nbsp;&nbsp;main()
&nbsp;&nbsp;File &quot;scratch.py&quot;, line 15, in main
&nbsp;&nbsp;&nbsp;&nbsp;1/0
ZeroDivisionError: integer division or modulo by zero
</code></pre><br />
The code involved was really easy to write.  I wrote a decorator called into_decorator with <a href="http://pypi.python.org/pypi/decorator">the decorator module</a>, but that&#8217;s not strictly necessary.  Here&#8217;s the code:<br />
<pre><code>
# vim: set expandtab ts=4 sw=4 filetype=python:

import pdb, sys
from decorator import decorator

@decorator
def into_debugger(f, *args, **kwargs):
&nbsp;&nbsp;&nbsp;&nbsp;try:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return f(*args, **kwargs)
&nbsp;&nbsp;&nbsp;&nbsp;except:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pdb.post_mortem()

def main():
&nbsp;&nbsp;&nbsp;&nbsp;x = 99
&nbsp;&nbsp;&nbsp;&nbsp;1/0 
&nbsp;&nbsp;&nbsp;&nbsp;
if __name__ == &#039;__main__&#039;:
&nbsp;&nbsp;&nbsp;&nbsp;if len(sys.argv) &gt; 1 and sys.argv[1] == &#039;--drop-into-debugger&#039;:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;into_debugger(main)()
&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;main()
</code></pre></p>
<p>That pdb.post_mortem function does the interesting work of inspecting the most recently caught exception.  The <a href="http://docs.python.org/library/pdb.html">pdb documentation</a> is pretty dang sparse, but in this case, I got what I needed.</p>
<p>Anyhow, I hope this helps somebody out.  I&#8217;ll probably be adding a &#8211;drop-into-debugger option on every script I write from now on.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tplus1.com/index.php/2009/12/24/add-an-option-for-your-script-to-drop-into-the-debugger/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>pitz has a CLI</title>
		<link>http://blog.tplus1.com/index.php/2009/11/17/pitz-has-a-cli/</link>
		<comments>http://blog.tplus1.com/index.php/2009/11/17/pitz-has-a-cli/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 02:32:08 +0000</pubDate>
		<dc:creator>matt</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[pitz]]></category>

		<guid isPermaLink="false">http://blog.tplus1.com/?p=514</guid>
		<description><![CDATA[I&#8217;ve exposed lots and lots of pitz functionality as command-line scripts.  Here&#8217;s the list so far:

$ pitz-help
&#160;&#160;&#160;&#160;pitz-abandon-task&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Abandon a task
&#160;&#160;&#160;&#160;pitz-add-task&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Walks through the setup of a new Task.
&#160;&#160;&#160;&#160;pitz-components&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;All components in the project
&#160;&#160;&#160;&#160;pitz-estimates&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; All estimates in the project
&#160;&#160;&#160;&#160;pitz-everything&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;No description
&#160;&#160;&#160;&#160;pitz-finish-task&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Finish a task
&#160;&#160;&#160;&#160;pitz-milestones&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;No description
&#160;&#160;&#160;&#160;pitz-my-tasks&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;List my tasks
&#160;&#160;&#160;&#160;pitz-people&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;All people in the project
&#160;&#160;&#160;&#160;pitz-prioritize-above&#160;&#160;&#160;&#160;&#160;&#160;Put one task in front of another task
&#160;&#160;&#160;&#160;pitz-prioritize-below&#160;&#160;&#160;&#160;&#160;&#160;Put one [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve exposed lots and lots of pitz functionality as command-line scripts.  Here&#8217;s the list so far:<br />
<pre><code>
$ pitz-help
&nbsp;&nbsp;&nbsp;&nbsp;pitz-abandon-task&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Abandon a task
&nbsp;&nbsp;&nbsp;&nbsp;pitz-add-task&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Walks through the setup of a new Task.
&nbsp;&nbsp;&nbsp;&nbsp;pitz-components&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;All components in the project
&nbsp;&nbsp;&nbsp;&nbsp;pitz-estimates&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; All estimates in the project
&nbsp;&nbsp;&nbsp;&nbsp;pitz-everything&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;No description
&nbsp;&nbsp;&nbsp;&nbsp;pitz-finish-task&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Finish a task
&nbsp;&nbsp;&nbsp;&nbsp;pitz-milestones&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;No description
&nbsp;&nbsp;&nbsp;&nbsp;pitz-my-tasks&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List my tasks
&nbsp;&nbsp;&nbsp;&nbsp;pitz-people&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;All people in the project
&nbsp;&nbsp;&nbsp;&nbsp;pitz-prioritize-above&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Put one task in front of another task
&nbsp;&nbsp;&nbsp;&nbsp;pitz-prioritize-below&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Put one task behind another task
&nbsp;&nbsp;&nbsp;&nbsp;pitz-recent-activity&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10 recent activities
&nbsp;&nbsp;&nbsp;&nbsp;pitz-setup&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; No description
&nbsp;&nbsp;&nbsp;&nbsp;pitz-shell&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Start an ipython session after loading in a ...
&nbsp;&nbsp;&nbsp;&nbsp;pitz-show&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Show detailed view of one entity
&nbsp;&nbsp;&nbsp;&nbsp;pitz-start-task&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Begin a task
&nbsp;&nbsp;&nbsp;&nbsp;pitz-statuses&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;All statuses in the project
&nbsp;&nbsp;&nbsp;&nbsp;pitz-tasks&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; All tasks in the project
&nbsp;&nbsp;&nbsp;&nbsp;pitz-todo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List every unstarted and started task in the...
&nbsp;&nbsp;&nbsp;&nbsp;pitz-unassign-task&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Take this task off somebody&#039;s list of stuff ...
</code></pre></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tplus1.com/index.php/2009/11/17/pitz-has-a-cli/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

