<?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>Benjamin Atkin &#187; python</title>
	<atom:link href="http://benatkin.com/tag/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://benatkin.com</link>
	<description></description>
	<lastBuildDate>Sun, 29 Jan 2012 03:51:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Front Range Pythoneers: Bowling Code Kata</title>
		<link>http://benatkin.com/2011/12/01/front-range-pythoneers-bowling-code-kata/</link>
		<comments>http://benatkin.com/2011/12/01/front-range-pythoneers-bowling-code-kata/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 07:03:21 +0000</pubDate>
		<dc:creator>Ben Atkin</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[practice]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://benatkin.com/?p=1063</guid>
		<description><![CDATA[For the November meeting of Front Range Pythoneers we did a bowling code kata. We worked as a group on the projector, but I also worked on my own version on my laptop. Here&#8217;s my code, which was fun to &#8230; <a href="http://benatkin.com/2011/12/01/front-range-pythoneers-bowling-code-kata/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>For the November meeting of <a href="http://www.meetup.com/frpythoneers/">Front Range Pythoneers</a> we did a bowling code kata. We worked as a group on the projector, but I also worked on my own version on my laptop. Here&#8217;s my code, which was fun to write. It&#8217;s a single file which contains its test cases and can be run on the command line or imported:</p>
<pre class="brush: python; title: ; notranslate">
import unittest

class Frame(object):
    def __init__(self, tenth=False):
        self.rolls = []
        self.tenth = tenth

    def full(self):
        if len(self.rolls) &gt;= self.max_rolls():
            return True
        if self.tenth:
            has_special = all([roll in ('X', '/') for roll in self.rolls])
            return len(self.rolls) == 2 and not has_special
        else:
            return self.strike()

    def roll(self, score):
        if self.full():
            raise RuntimeError('attempted to record a roll on a full frame')
        self.rolls.append(score)

    def pins(self):
        if len(self.rolls) == 0:
            return 0
        if self.strike() or self.spare():
            return 10
        else:
            return sum([int(roll) for roll in self.rolls])

    def first_roll_pins(self):
        if len(self.rolls) == 0:
            return 0
        elif self.rolls[0] == 'X':
            return 10
        else:
            return int(self.rolls[0])

    def score(self, subsequent_frames):
        if self.tenth:
            return self.tenth_frame_score()

        score = self.pins()
        if self.strike():
            score += sum([frame.pins() for frame in subsequent_frames])
        elif self.spare():
            if len(subsequent_frames) &gt; 0:
                score += subsequent_frames[0].first_roll_pins()
        return score

    def tenth_frame_score(self):
        return min(Game(''.join(self.rolls)).score(), 40)

    def strike(self):
        return len(self.rolls) &gt; 0 and self.rolls[0] == 'X'

    def spare(self):
        return len(self.rolls) &gt; 0 and self.rolls[-1] == '/'

    def max_rolls(self):
        return 3 if self.tenth else 2

class Game(object):
    def __init__(self, roll_scores=''):
        self.frames = []
        for score in roll_scores:
            self.roll(score)

    def roll(self, score):
        if len(self.frames) == 0 or self.frames[-1].full():
            tenth = len(self.frames) == 9
            self.frames.append(Frame(tenth))
        self.frames[-1].roll(score)

    def score(self):
        return sum(self.frame_scores())

    def frame_scores(self):
        frame_scores = []
        for frame_index in xrange(len(self.frames)):
            frame = self.frames[frame_index]
            subsequent_frames = []
            if frame.strike() or frame.spare():
                subsequent_frames = self.frames[frame_index+1:]
                added_frames = 1
                if frame.strike() and len(subsequent_frames) &gt; 0:
                    added_frames = 2 if subsequent_frames[0].strike() else 1
                subsequent_frames = subsequent_frames[:added_frames]
            frame_scores.append(frame.score(subsequent_frames))
        return frame_scores

class GameTest(unittest.TestCase):
    def test_initial_strike(self):
        self.assertEqual(Game('X').score(), 10)

    def test_two_strikes(self):
        self.assertEqual(Game('XX').score(), 20+10)

    def test_three_strikes(self):
        self.assertEqual(Game('XXX').score(), 30+20+10)

    def test_strike_spare_strike(self):
        self.assertEqual(Game('X9/X').score(), 20+20+10)

    def test_strike_strike_spare(self):
        self.assertEqual(Game('XX9/').score(), 30+20+10)
        self.assertEqual(Game('XX9/71').score(), 30+20+17+8)

    def test_perfect_game(self):
        game = Game('X'*12)
        self.assertEqual(len(game.frames), 10)
        self.assertEqual(game.score(), 300)

    def test_made_up_game(self):
        game = Game('X907/818/X70070/72')
        self.assertEqual(len(game.frames), 10)
        self.assertEqual(game.score(), 132)

if __name__ == '__main__':
    unittest.main()
</pre>
<p>I think that the tenth frame calculation is incorrect. My limited understanding of bowling slowed me down a fair bit. I got an object system that I&#8217;m fairly happy with, though!</p>
]]></content:encoded>
			<wfw:commentRss>http://benatkin.com/2011/12/01/front-range-pythoneers-bowling-code-kata/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Downgrading Django to 1.1.2</title>
		<link>http://benatkin.com/2010/06/04/downgrading-django-to-1-1-2/</link>
		<comments>http://benatkin.com/2010/06/04/downgrading-django-to-1-1-2/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 20:31:59 +0000</pubDate>
		<dc:creator>Ben Atkin</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[bugs]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[pip]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://benatkin.com/weblog/?p=668</guid>
		<description><![CDATA[I had some issues upgrading to Django 1.2.1, and needed to roll Django back to 1.1.2. I searched for &#8220;Downgrading Django&#8221;, and didn&#8217;t find instructions, so now that I&#8217;ve figured it out, I&#8217;m posting instructions here. First, if you&#8217;re using &#8230; <a href="http://benatkin.com/2010/06/04/downgrading-django-to-1-1-2/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I had some issues upgrading to Django 1.2.1, and needed to roll Django back to 1.1.2. I searched for &#8220;Downgrading Django&#8221;, and didn&#8217;t find instructions, so now that I&#8217;ve figured it out, I&#8217;m posting instructions here.</p>
<p>First, if you&#8217;re using easy_install, I suggest switching to <a href="http://pypi.python.org/pypi/pip">pip</a>. It has more features, is better designed, and uses the same repositories, so it&#8217;s easy to upgrade. To install it, type <strong>sudo easy_install pip</strong>.</p>
<p>To install Django 1.1.2, type <strong>sudo pip install Django==1.1.2</strong>. When I ran this, <strong>pip</strong> automatically removed the newer version of Django, and the two glitches I was encountering with the admin interface went away. Once I figure out what caused the glitches, I&#8217;ll upgrade back to <a href="http://docs.djangoproject.com/en/dev/releases/1.2/">Django 1.2 so I can take advantage of its new features</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://benatkin.com/2010/06/04/downgrading-django-to-1-1-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>setting up a default virtualenv</title>
		<link>http://benatkin.com/2009/12/09/setting-up-a-default-virtualenv/</link>
		<comments>http://benatkin.com/2009/12/09/setting-up-a-default-virtualenv/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 01:11:47 +0000</pubDate>
		<dc:creator>Ben Atkin</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[configuration]]></category>
		<category><![CDATA[prompt]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[virtualenv]]></category>

		<guid isPermaLink="false">http://benatkin.com/weblog/?p=464</guid>
		<description><![CDATA[After using virtualenv for months, I finally got around to putting my main virtualenv into my bash profile. It&#8217;s really simple. All I had to do was add the following to ~/.bash_profile: # python virtualenv source /Users/ben/virtualenv/pearl/bin/activate This worked, but &#8230; <a href="http://benatkin.com/2009/12/09/setting-up-a-default-virtualenv/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>After using <a href="http://pypi.python.org/pypi/virtualenv">virtualenv</a> for months, I finally got around to putting my main virtualenv into my bash profile. It&#8217;s really simple. All I had to do was add the following to ~/.bash_profile:</p>
<p><code># python virtualenv<br />
source /Users/ben/virtualenv/pearl/bin/activate</code></p>
<p>This worked, but there was one thing I wanted to turn off. The <em>activate</em> script that virtualenv creates adds the name of the current virtualenv to the front of the prompt. This is useful when switching between virtualenv directories, but it&#8217;s not very useful to me when I&#8217;m on the default virtualenv. So I moved my prompt definition to the bottom of the file, so it gets executed after the <em>source</em> command above.</p>
<p><code># prompt (moved after virtualenv so it isn't shown)<br />
PS1="\[\e[31;40m\]\@ \[\e[32;40m\]\w \[\e[36;40m\]\$\[\e[0m\] "</code></p>
<p>By the way, to keep the prompt I use the most often short, I set my own colors. It&#8217;s easy for me to tell that it&#8217;s my main shell, and since it&#8217;s my main shell, I know the username and hostname associated with it.</p>
]]></content:encoded>
			<wfw:commentRss>http://benatkin.com/2009/12/09/setting-up-a-default-virtualenv/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Graphing retweets with Python and GraphViz</title>
		<link>http://benatkin.com/2009/04/27/graphing-retweets-with-python-and-graphviz/</link>
		<comments>http://benatkin.com/2009/04/27/graphing-retweets-with-python-and-graphviz/#comments</comments>
		<pubDate>Tue, 28 Apr 2009 06:37:09 +0000</pubDate>
		<dc:creator>Ben Atkin</dc:creator>
				<category><![CDATA[uncategorized]]></category>
		<category><![CDATA[graphs]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://benatkin.com/weblog/?p=308</guid>
		<description><![CDATA[On the microblogging site twitter, a blog post is called an update, or informally, a tweet. When someone copies a tweet and posts it to their twitter feed, it&#8217;s called a retweet. Sometimes opinions are retweeted by those who share &#8230; <a href="http://benatkin.com/2009/04/27/graphing-retweets-with-python-and-graphviz/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>On the microblogging site twitter, a blog post is called an update, or informally, a tweet. When someone copies a tweet and posts it to their twitter feed, it&#8217;s called a retweet. Sometimes opinions are retweeted by those who share them, other times it&#8217;s information, and other times it&#8217;s silly memes. This evening, a local friend of mine on twitter started a meme by saying &#8220;tweet.&#8221; and asking for a retweet. One person who retweeted it got his message retweeted.</p>
<p><img src="http://benatkin.com/weblog/wp-content/uploads/2009/04/picture-5.png" alt="retweets" title="retweets" width="474" height="316" class="alignnone size-full wp-image-309"></p>
<p>I know I&#8217;m not the first person to graph retweets, but being curious as to what this particular graph would look like, I decided to do a graph in Python as a programming exercise. I did it using a GraphViz library. The code is here:</p>
<pre class="prettyprint" style="border: none">
import pydot

graph = pydot.Dot('rt', graph_type='digraph')
tweeps = ('tysoncrosbie',
           ('phxreguy',
             ('sbowerman',
               ('phxwebguy', 'leaky_tiki'),
               'refriedchicken')),
           'vhgill',
           'Yartibise')

def add_edge(source, dest):
  graph.add_edge(pydot.Edge(source, dest))

def first_flat(tree):
  if isinstance(tree, tuple):
    return first_flat(tree[0])
  else:
    return tree

def find_edges(tree):
  if isinstance(tree, tuple):
    source = tree[0]
    for dest in tree[1:]:
      add_edge(source, first_flat(dest))
      find_edges(dest)

find_edges(tweeps)
graph.write_png('rt_graph.png')
</pre>
<p>The code takes a nested list structure (a tree) and produces edges from it, which can be graphed by GraphViz. It uses pydot, a GraphViz library for Python. Here is the resulting image:</p>
<p><img src="http://benatkin.com/weblog/wp-content/uploads/2009/04/rt_graph1.png" alt="rt_graph1" title="rt_graph1" width="511" height="443" class="alignnone size-full wp-image-320"></p>
<p>Observations:</p>
<ul>
<li>
<b>Python doesn&#8217;t have a built-in list flattening function.</b> This was irritating. Ruby&#8217;s is Array#flatten. It would have been so much nicer to have been able to grab the first element of a flattened list rather than write the first_flat function or copy/paste a list-flattening function from the Internet.</li>
<li>
<b>pydot is really simple to use.</b> I liked how it could produce a png file. I was planning just to have it create a dot file and then use GraphViz to create a png, but when I saw the write_png function I decided to just use that.</li>
<li>
<b>GraphViz has reasonable defaults.</b> It produced a nice-looking graph on the first try. I think that&#8217;s a big part of why GraphViz is as popular as it is.</li>
</ul>
<p>I was hoping to have a little more to show for tomorrow&#8217;s Python Interest Group meeting, but this will have to do!</p>
]]></content:encoded>
			<wfw:commentRss>http://benatkin.com/2009/04/27/graphing-retweets-with-python-and-graphviz/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

