<?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:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" version="2.0">
<channel>
<title><![CDATA[Unified Python Planet]]></title>
<description><![CDATA[A uniqued union of the Official and Unofficial Python planet feeds.  Generated by Atomisator FTW!]]></description>
<link>http://feeds2.feedburner.com/UnifiedPythonPlanet</link>
<language>en</language>
<copyright>Copyright 2008, Atomisator</copyright>
<pubDate>Sat, 15 Mar 2008 00:15:05 +0200</pubDate>
<lastBuildDate>Sat, 15 Mar 2008 00:15:05 +0200</lastBuildDate>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/UnifiedPythonPlanet" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="unifiedpythonplanet" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
    <title><![CDATA[Caktus Consulting Group: Narrowing the Gender Gap in the Open Source community]]></title>
    <description><![CDATA[<p>Diversity is important in a workplace environment. Having different points of view from people with different life experiences brings <a href="http://www.brighthub.com/office/human-resources/articles/90910.aspx">creative new ideas and innovative solutions</a> to the software development process. As a team of web developers that designs and builds custom web applications, creativity and gender diversity, I would argue, are closely tied and both crucial to the success of our projects.</p>
<p>Software development is traditionally a field dominated by men. The presence of women in programming is commanding more attention at conferences and events, particularly in recent years. There are many initiatives within the Python community to promote involvement, such as the group <a href="http://www.meetup.com/Women-Who-Code-SF/">Women Who Code</a>, and the long-term benefits of efforts like these cannot be overstated. At Caktus, three of the ten current members of our Django development staff are female, and we are actively working to further equalize the gender balance through future hires.</p>
<p>One part of closing the gender gap in programming communities involves creating a safe and inclusive environment for all parties, both in the workplace and at community events. This begins with strong employment policies on harassment &mdash; which we have implemented here at Caktus &mdash; and also extends to implementing policies at conferences or other events relevant to the development community. This blog post comes out of several recent events in the broader tech community that Caktus is a part of.  This includes two blog posts that drew a lot of attention, and two corporate events that demonstrated clearly for us how pervasive sexism still is in our industry.</p>
<p>In March, Katie Cunningham, a fellow Django developer and friend made through DjangoCon, wrote an excellent and widely read blog post titled &quot;<a href="http://therealkatie.net/blog/2012/mar/21/lighten-up/">Lighten Up</a>.&quot; The post details a story that is all too common in our industry, that of ongoing, but usually subtle sexist jokes and comments that serve only, whether intentionally or not, to gradually demoralize and discourage those to whom they are addressed. She discusses how the typical response, should someone get upset by such a &quot;joke&quot; or comment, is simply to &quot;lighten up&quot; and &quot;stop being so sensitive.&quot; I can see how that would get really old. Fast. In fact, just in reading up for writing this post, I was blown away by the number of comments in response to posts such as Katie's that fit exactly that description.</p>
<p>Just a couple weeks ago, the computer manufacturer Dell hosted a summit in Copenhagen. Dell hired a &quot;comedian&quot; to MC the event, who proceeded to entertain the attendees with <a href="http://news.cnet.com/8301-31322_3-57431869-256/why-we-need-to-keep-talking-about-women-in-tech/?tag=mncol;txt">a variety of sexist jokes</a>, acclaiming the &quot;success&quot; of the IT community as indicated by its male-dominated culture, and included a suggestion to the mostly male attendees that they go home and tell their partners to &quot;shut up bitch.&quot; Dell has finally put out <a href="https://plus.google.com/117161668189080869053/posts/5Zg5FdFEydi">an apology</a> about what happened, but the consensus seems to be that it's <a href="http://news.cnet.com/8301-31322_3-57434780-256/dell-apologizes-for-hiring-sexist-summit-moderator/">weak at best</a> and, given its tardiness, lost any sincerity it may once have had.</p>
<p>In closing, I&rsquo;d like to draw attention to one other aspect of the software development community, particularly at conferences, that often tends to aggravate any pre-existing sexism that might exist in the community. Last month, Ryan Funduk wrote an extensive and much-debated blog post, titled &quot;<a href="http://ryanfunduk.com/culture-of-exclusion/">Our Culture of Exclusion</a>,&quot; about the pervasiveness of drinking at many programming conferences. He also discusses how, all too often, these environments are ripe with sexist or racist jokes (or worse) that quickly erode any efforts to further diversify such communities. One example that he highlights is the daily deal API provider Sqoot, who alienated and offended many when they suggested that women are<a href="http://www.readwriteweb.com/enterprise/2012/03/how-casual-sexism-put-sqoot-in.php"> </a><a href="http://www.readwriteweb.com/enterprise/2012/03/how-casual-sexism-put-sqoot-in.php">better fit to serve beer than to program</a>. Sqoot made<a href="http://blog.sqoot.com/we-can-do-better-an-apology-from-sqoot"> </a><a href="http://blog.sqoot.com/we-can-do-better-an-apology-from-sqoot">several apologies</a> about this unfortunate advertisement, but many of them still fell short and only worsened the offense, as this response from<a href="https://twitter.com/#%21/gayle"> </a><a href="https://twitter.com/#%21/gayle">Gayle McDowell</a> aptly sums up:</p>
<blockquote>Your language, as far as I understand it, is making the assumption that all coders are male, that all are straight, that women are sexual objects offered as a reward (HIGHLY inappropriate in a professional context), and that the women are there to serve them.</blockquote>
<p>She goes on to suggest an appropriate response if and when events like this do happen:</p>
<blockquote>People screw up sometimes. It happens. A TON of people (both men and women) have done equally offensive things. // But when you do it, you need to own up to it and think about what you've done. Not lie about it, as you're doing now.</blockquote>
<p>Clearly, we need to have policies in place for handling instances of sexist or racist jokes and sexual harassment. When they do happen, McDowell says, one needs to take responsibility and own up to the mistakes one has made in an honest way.</p>
<p>The bar has been set, and I think it&rsquo;s worth noting that several lessons can be taken from these events and applied to our own communities. Caktus is a long-time sponsor of several conferences relevant to the work that we do. Along with this blog post, Caktus is asking conference organizers and other sponsors to join us in the following effort: Moving forward, Caktus will require that a <strong>zero-tolerance sexual harassment policy</strong> is established and <strong>enforced</strong> by the organizers of any conference that we sponsor or attend. We want to ensure that our community events are safe, welcoming, and supportive for all of our colleagues &mdash; both male and female. While drinking can certainly make things worse, it is not the root of the problem. To overcome these issues, we need to talk about them more, continue to raise awareness, and treat all people in our workplaces and communities with the professionalism and respect that they deserve.</p>]]></description>
    <link><![CDATA[http://www.caktusgroup.com/blog/2012/05/24/narrowing-gender-gap-open-source-community/]]></link>
    <pubDate>2012-05-24 20:44:57</pubDate>
  </item>
  <item>
    <title><![CDATA[Mike Driscoll: wxPython for Python 3 is Almost Here!!!]]></title>
    <description><![CDATA[<p>Robin Dunn, creator and mastermind behind wxPython, announced today on his <a href="http://wxpython.org/blog/2012/05/24/its-alive/" target="_blank">blog </a>and the <a href="https://groups.google.com/forum/?fromgroups#!topic/wxpython-dev/p5HQHZgT_XE" target="_blank">wxPython-dev mailing list</a> that he had gotten wxPython 2.9 (Phoenix) to build successfully for Python 3.2 on Mac. In fact, he posted a <a href="http://wxpython.org/Phoenix/ItsAlive/" target="_blank">Quicktime video</a> that shows the build and the tests running in Python 3! According to wxPython-dev, once they have some Python 3 buildbot slaves set up, then snapshot builds can be made and posted <a href="http://wxpython.org/Phoenix/snapshot-builds/">here</a>.</p>
<p>I&#8217;m pretty excited! Now if only the Python Imaging Library would convert too&#8230;</p>]]></description>
    <link><![CDATA[http://www.blog.pythonlibrary.org/2012/05/24/wxpython-for-python-3-is-almost-here/]]></link>
    <pubDate>2012-05-24 18:27:11</pubDate>
  </item>
  <item>
    <title><![CDATA[Robin Dunn: It’s Alive!]]></title>
    <description><![CDATA[<p>Watch as the Phoenix spreads her wings over Python 3:</p>
<p><a href="http://wxpython.org/Phoenix/ItsAlive/">http://wxpython.org/Phoenix/ItsAlive/</a></p>]]></description>
    <link><![CDATA[http://wxPython.org/blog/2012/05/24/its-alive/]]></link>
    <pubDate>2012-05-24 16:52:51</pubDate>
  </item>
  <item>
    <title><![CDATA[Kristján Valur: Zombieframes.  A gratuitous optimization?]]></title>
    <description><![CDATA[<p>Examing a recent crash case, I stumbled across this code in frameobject.c:</p>
<pre class="brush: c">
PyFrameObject *
PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals,
PyObject *locals)
...
if (code-&gt;co_zombieframe != NULL) {
f = code-&gt;co_zombieframe;
code-&gt;co_zombieframe = NULL;
_Py_NewReference((PyObject *)f);
assert(f-&gt;f_code == code);
}
</pre>
<p>Intrigued by the name, I examined the header where it is defined, code.h:</p>
<pre class="brush: c">
...
void *co_zombieframe; /* for optimization only (see frameobject.c) */
...
} PyCodeObject;
</pre>
<p>It turns out that for every PyCodeObject object that has been executed, a PyFrameObject of a suitable size is cached and kept with the code object. Now, caching is fine and good, but this cache is unbounded. Every code object has the potential to hang on to a frame, which may then never be released.<br />
Further, there is a separate freelist cache for PyFrameObjects already, in case a frame is not found on the code object:</p>
<pre class="brush: c">
if (free_list == NULL) {
f = PyObject_GC_NewVar(PyFrameObject, &amp;amp;PyFrame_Type,
extras);
if (f == NULL) {
Py_DECREF(builtins);
return NULL;
}
}
else {
assert(numfree &gt; 0);
--numfree;
f = free_list;
free_list = free_list-&gt;f_back;
...
</pre>
<p>Always concious about memory these days, I tried disabling this in version 3.3 and running the pybench test. I was not able to see any conclusive difference in execution speed.</p>
<h2>Update:</h2>
<p>Disabling the zombieframe on the PS3 shaved off some 50k on startup.  Not the jackpot, but still, small things add up.</p>
<blockquote><p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
PYBENCH 2.1<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
* using CPython 3.3.0a3+ (default, May 23 2012, 20:02:34) [MSC v.1600 64 bit (AMD64)]<br />
* disabled garbage collection<br />
* system check interval set to maximum: 2147483647<br />
* using timer: time.perf_counter<br />
* timer: resolution=2.9680909446810176e-07, implementation=QueryPerformanceCounter()</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Benchmark: nozombie<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>Rounds: 10<br />
Warp: 10<br />
Timer: time.perf_counter</p>
<p>Machine Details:<br />
Platform ID: Windows-7-6.1.7601-SP1<br />
Processor: Intel64 Family 6 Model 26 Stepping 5, GenuineIntel</p>
<p>Python:<br />
Implementation: CPython<br />
Executable: D:pydevhgcpython2pcbuildamd64python.exe<br />
Version: 3.3.0a3+<br />
Compiler: MSC v.1600 64 bit (AMD64)<br />
Bits: 64bit<br />
Build: May 23 2012 20:02:34 (#default)<br />
Unicode: UCS4</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Comparing with: zombie<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>Rounds: 10<br />
Warp: 10<br />
Timer: time.perf_counter</p>
<p>Machine Details:<br />
Platform ID: Windows-7-6.1.7601-SP1<br />
Processor: Intel64 Family 6 Model 26 Stepping 5, GenuineIntel</p>
<p>Python:<br />
Implementation: CPython<br />
Executable: D:pydevhgcpython2pcbuildamd64python.exe<br />
Version: 3.3.0a3+<br />
Compiler: MSC v.1600 64 bit (AMD64)<br />
Bits: 64bit<br />
Build: May 23 2012 20:00:42 (#default)<br />
Unicode: UCS4</p>
<p>Test minimum run-time average run-time<br />
this other diff this other diff<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
BuiltinFunctionCalls: 51ms 52ms -3.3% 52ms 53ms -2.0%<br />
BuiltinMethodLookup: 33ms 33ms +0.0% 34ms 34ms +0.8%<br />
CompareFloats: 50ms 50ms +0.1% 50ms 50ms +0.4%<br />
CompareFloatsIntegers: 99ms 98ms +0.8% 99ms 99ms +0.6%<br />
CompareIntegers: 77ms 77ms -0.5% 77ms 77ms -0.3%<br />
CompareInternedStrings: 60ms 60ms +0.0% 61ms 61ms -0.1%<br />
CompareLongs: 46ms 45ms +1.5% 46ms 45ms +1.2%<br />
CompareStrings: 61ms 59ms +3.6% 61ms 59ms +3.6%<br />
ComplexPythonFunctionCalls: 60ms 58ms +3.3% 60ms 58ms +3.2%<br />
ConcatStrings: 48ms 47ms +2.4% 48ms 47ms +2.1%<br />
CreateInstances: 58ms 57ms +1.3% 59ms 58ms +1.3%<br />
CreateNewInstances: 43ms 43ms +1.1% 44ms 44ms +1.1%<br />
CreateStringsWithConcat: 79ms 79ms -0.3% 79ms 79ms -0.1%<br />
DictCreation: 71ms 71ms +0.4% 72ms 72ms +1.0%<br />
DictWithFloatKeys: 72ms 70ms +2.1% 72ms 71ms +1.8%<br />
DictWithIntegerKeys: 46ms 46ms +0.7% 46ms 46ms +0.4%<br />
DictWithStringKeys: 41ms 41ms +0.0% 41ms 41ms -0.1%<br />
ForLoops: 35ms 37ms -4.0% 35ms 37ms -4.0%<br />
IfThenElse: 64ms 64ms -0.1% 64ms 64ms -0.4%<br />
ListSlicing: 49ms 50ms -1.0% 53ms 53ms -0.8%<br />
NestedForLoops: 54ms 51ms +6.7% 55ms 51ms +6.7%<br />
NestedListComprehensions: 54ms 54ms -0.7% 54ms 55ms -2.2%<br />
NormalClassAttribute: 94ms 94ms +0.1% 94ms 94ms +0.1%<br />
NormalInstanceAttribute: 54ms 54ms +0.3% 54ms 54ms +0.2%<br />
PythonFunctionCalls: 58ms 57ms +0.8% 58ms 58ms +0.6%<br />
PythonMethodCalls: 65ms 61ms +6.3% 66ms 62ms +5.9%<br />
Recursion: 84ms 85ms -1.0% 85ms 85ms -0.9%<br />
SecondImport: 74ms 76ms -2.5% 74ms 77ms -3.5%<br />
SecondPackageImport: 75ms 78ms -3.8% 76ms 79ms -3.9%<br />
SecondSubmoduleImport: 163ms 169ms -3.4% 164ms 170ms -3.3%<br />
SimpleComplexArithmetic: 43ms 43ms +1.0% 43ms 43ms +1.0%<br />
SimpleDictManipulation: 80ms 78ms +2.2% 81ms 79ms +2.4%<br />
SimpleFloatArithmetic: 42ms 42ms +0.1% 42ms 42ms -0.0%<br />
SimpleIntFloatArithmetic: 52ms 53ms -1.2% 52ms 53ms -1.1%<br />
SimpleIntegerArithmetic: 52ms 52ms -0.7% 52ms 53ms -0.8%<br />
SimpleListComprehensions: 45ms 45ms -0.2% 45ms 45ms +0.3%<br />
SimpleListManipulation: 44ms 46ms -4.0% 44ms 46ms -3.9%<br />
SimpleLongArithmetic: 32ms 32ms -0.9% 32ms 32ms -0.1%<br />
SmallLists: 58ms 57ms +1.2% 58ms 67ms -12.8%<br />
SmallTuples: 64ms 65ms -0.5% 65ms 65ms -0.2%<br />
SpecialClassAttribute: 148ms 149ms -0.8% 149ms 150ms -1.0%<br />
SpecialInstanceAttribute: 54ms 54ms +0.2% 54ms 54ms +0.0%<br />
StringMappings: 120ms 117ms +2.5% 120ms 117ms +2.5%<br />
StringPredicates: 62ms 62ms +0.9% 62ms 62ms +1.0%<br />
StringSlicing: 69ms 68ms +1.6% 69ms 68ms +2.1%<br />
TryExcept: 37ms 37ms +0.0% 37ms 37ms +0.5%<br />
TryFinally: 40ms 37ms +6.7% 40ms 37ms +6.5%<br />
TryRaiseExcept: 19ms 20ms -1.0% 20ms 20ms -0.4%<br />
TupleSlicing: 65ms 65ms +0.5% 66ms 65ms +1.2%<br />
WithFinally: 57ms 56ms +1.9% 57ms 56ms +2.1%<br />
WithRaiseExcept: 53ms 53ms +0.3% 54ms 54ms -0.8%<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Totals: 3154ms 3145ms +0.3% 3176ms 3177ms -0.0%</p>
<p>(this=nozombie, other=zombie)</p></blockquote>
<p>I&#8217;m going to remove this weird, unbounded cache from the python interpreter we use on the PS3.</p>]]></description>
    <link><![CDATA[http://blog.ccpgames.com/kristjan/2012/05/23/zombieframes-a-gratuitous-optimization/]]></link>
    <pubDate>2012-05-24 14:14:56</pubDate>
  </item>
  <item>
    <title><![CDATA[PyCon: PyCon DE 2012 - Registration Open]]></title>
    <description><![CDATA[We are glad to announce that the registration for the&nbsp;<a href="http://2012.de.pycon.org/">second PyCon DE</a>&nbsp;in Leipzig is open. You can now buy&nbsp;<a href="http://2012.de.pycon.org/tickets/">tickets </a>at the&nbsp;early-bird rate until end of June before prices will go up. Don't miss the opportunity to come the larges meeting of the German-speaking Python community and secure your ticket now.<br /><br />If you plan not only to come but also to&nbsp;contribute, you can <a href="http://2012.de.pycon.org/proposals/submit/">submit</a> a proposal for a talk or a tutorial. A wide&nbsp;variety&nbsp;of Python-related&nbsp;topics are&nbsp;welcome. More details in an&nbsp;<a href="http://pycon.blogspot.de/2012/05/pycon-de-2012-call-for-proposals-for.html">earlier post</a>.<br /><br />The&nbsp;<a href="http://2012.de.pycon.org/">second PyCon DE</a>&nbsp;will be in Leipzig from October 29 through November 3, 2012. One tutorial day, three days with talks and two days with a barcamp, code retreat &nbsp;and sprints will provide different ways to communicate about Python. There will be social events to give everybody ample opportunity to network with like-minded Pythonistas.<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/11638628-6418397215610179535?l=pycon.blogspot.com" alt="" /></div>]]></description>
    <link><![CDATA[http://pycon.blogspot.com/2012/05/pycon-de-2012-registration-open.html]]></link>
    <pubDate>2012-05-24 13:09:02</pubDate>
  </item>
  <item>
    <title><![CDATA[Python Insider: Recent Windows Changes in Python 3.3]]></title>
    <description><![CDATA[<div class="document" id="recent-windows-changes-in-python-3-3">
The Windows build of Python 3.3 has recently seen changes that could use a look from the community throughout our alpha and beta cycle. The first change is the long requested addition of Python to the system <tt class="docutils literal">Path</tt> variable, which was completed in the installer. Secondly, the build was upgraded to Visual Studio 2010.<br />
<br />
<div class="section" id="python-on-the-path">
<h4>


Python on the Path</h4>
A long requested feature, especially from beginners to those involved in education and training, has been the ability for the Python installer to place itself in the system <tt class="docutils literal">Path</tt> environment variable. Having the following message appear when you try to run a simple exercise is not a great first experience:<br />
<blockquote>
<tt class="docutils literal">'python' is not recognized as an internal or external command, operable program or batch file.</tt></blockquote>
Because of that, the first post-install step by many users is to edit the <tt class="docutils literal">Path</tt> environment variable manually to insert the C:Python33 directory. This allows the user to simply type <tt class="docutils literal">python</tt> on the command line and have it open <tt class="docutils literal"><span class="pre">C:\\Python33\\python.exe</span></tt> -- a very desirable feature for a majority of users. In fact, it's such a common post-install step that there are a huge amount of tutorials either about this step by itself or tutorials where their setup introduces this step before moving on.<br />
<blockquote>
<img alt="http://i.imgur.com/aixuY.png" src="http://i.imgur.com/aixuY.png" />
</blockquote>
The easiest part of the whole thing was <a class="reference external" href="http://hg.python.org/cpython/rev/4e9f1017355f">the code</a>. <tt class="docutils literal">Path</tt> manipulation in the installer consists of adding a new feature to the Feature table, then the Environment table may be updated based on selection of the Path feature. If the feature was selected, the Environment table is modified in a way that the <tt class="docutils literal">Path</tt> is prepended to and will be correctly cleaned up on uninstallation.<br />
<br />
The harder part was deciding how to go about the change. If you're going to provide <tt class="docutils literal">Path</tt> manipulation, the major questions are to do it by default or not, and to prepend or append to the <tt class="docutils literal">Path</tt>.<br />
<br />
We decided that it wasn't appropriate to make this a default feature. For one, in the dual-version state many users are running in, we run the risk of users running through the installer and putting their system into a state they aren't prepared for. We don't want to change the meaning of <tt class="docutils literal">python</tt> when executed on the command line without the user asking for it. On one hand it's a very beginner focused feature in that it gets a first-timer successfully up and running with ease. However, it's also an advanced feature in that it takes a good understanding of what it's going to do to the users who have 2.6, 2.7, 3.2, and now 3.3 on their machines. We think the best solution for all is to leave it up to them and include an explanation.<br />
<br />
The other part we had to think about was whether to prepend or append to the path. While some believe that appending to the path is the more friendly way to work with the system, it would seem to be of limited utility given that the feature is added this late in the game. Instead we went the route of prepending the installation folder, e.g., C:\Python33, in order to make sure this feature is actually useful to our users.<br />
<br />
If you have questions or comments, please feel free to raise them on python-dev or see  <a class="reference external" href="http://bugs.python.org/issue3561">Issue 3561</a>.<br />
<br /></div>
<div class="section" id="transition-to-visual-studio-2010">
<h4>


Transition to Visual Studio 2010</h4>
In time for the last alpha release, we've updated our build tools from Visual Studio 2008 to 2010.<br />
Many potential contributors as well as general Python users have long moved to work environments that use Visual Studio 2010. During a "bug day" some months ago, we had two or three patches come from interested first-timers who found our VS2008 solution not working in VS2010. Over time we received a few more contributions and bug reports on the topic, as well as some chatter in IRC about being behind the curve.<br />
<br />
On top of that, my employer at the time moved to VS2010 as well as the employers of at least one other core maintainer, so we were already operating on ports for our companies.<br />
<br />
When it came time to think about what to do for Python 3.3, moving to VS2010 became a <em>must have</em> due to our release schedule. Staying with VS2008 for 3.3 would put us into the middle of 2014 as the next time we could release on a new version. That would leave us at least two versions behind, with VS2010 as well as VS11 being available by then.<br />
<br />
Another reason is the relative ease of porting between VS2010 and VS11. Once we got ourselves on to 2010, moving on to 11 would not be that hard. VS11 currently reads our VS2010 files without change if you want to use the IDE features of VS11. However, there'd need to be another port in order to use the VS11 compiler suite, but it seems to require minimal effort. Just following the VS11 wizard produced a functioning executable, although it didn't build cleanly.<br />
<br />
<div class="section" id="where-to-get-visual-studio-2010">
<h5>


Where to get Visual Studio 2010?</h5>
As usual, Microsoft provides a zero-cost version of Visual Studio 2010 in the name Visual C++ Express, available at <a class="reference external" href="http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express">http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express</a>. While there are <a class="reference external" href="http://msdn.microsoft.com/en-us/library/hs24szh9(v=vs.100).aspx">some differences</a> between the Express version and the for-purchase versions, the Express version is used successfully by many contributors.<br />
<br />
The fine folks at Microsoft's <a class="reference external" href="http://www.microsoft.com/en-us/openness/default.aspx#home">Open Source Technology Center</a> have provided the core contributors with MSDN licenses free of charge, allowing for access to the full versions of Visual Studio among other products. The full versions of Visual Studio support 64-bit compilation which comes in handy for our amd64 releases, which have been available since 2.5.<br />
<br /></div>
</div>
<div class="section" id="help-us-out-try-the-alphas-and-betas">
<h4>


Help us out -- try the alphas and betas!</h4>
With a change to the installer, a new build system, and the <a class="reference external" href="http://docs.python.org/dev/whatsnew/3.3.html">other great changes</a> we have in store, the more feedback we hear from the community during the development cycle, the better we can make this release. If you have a chance to run your projects on Python 3.3, <a class="reference external" href="http://bugs.python.org/">http://bugs.python.org</a> is always open for your reports. You've even got a month to get feature requests in and completed!<br />
<br />
The last alpha release is scheduled for this weekend, and the first beta release is scheduled for June 24. You can download our 3.3.0 releases at <a class="reference external" href="http://www.python.org/download/releases/3.3.0/">http://www.python.org/download/releases/3.3.0/</a>.</div>
</div><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/3941553907430899163-2117644518967524777?l=blog.python.org" alt="" /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=yIl2AUoC8zA" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:-BTjWOF_DHI" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:F7zBnMyn0Lo" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonInsider?i=rWPwayEXWfE:cAxThx2AZbA:V_sGLiPBpWU" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonInsider?a=rWPwayEXWfE:cAxThx2AZbA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/PythonInsider?d=qj6IDK7rITs" border="0" /></a>
</div><img src="http://feeds.feedburner.com/~r/PythonInsider/~4/rWPwayEXWfE" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/PythonInsider/~3/rWPwayEXWfE/recent-windows-changes-in-python-33.html]]></link>
    <pubDate>2012-05-24 13:08:43</pubDate>
  </item>
  <item>
    <title><![CDATA[Python Software Foundation: 2012 Q1 Community Service Awards]]></title>
    <description><![CDATA[<div class="document" id="q1-community-service-awards">
The Foundation wishes to thank Carl Trachte and Audrey Roy for their work in the Python community with <a class="reference external" href="http://www.python.org/community/awards/psf-awards/">Community Service Awards</a> for the first quarter of 2012.<br />
<br />
Carl has put significant effort into diversifying and supporting non-English speaking writers for the Python Wiki.<br />
<br />
Audrey also put in a lot of time diversifying the community with her work in creating the PyLadies group as well speaking on outreach issues as numerous conferences.<br />
<br />
On behalf of the Python community, the PSF thanks Carl and Audrey for their time and effort!</div><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/8520-1810795452173646647?l=pyfound.blogspot.com" alt="" /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=g2PLacIMnXU:0NZqOv15ZNc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?d=yIl2AUoC8zA" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=g2PLacIMnXU:0NZqOv15ZNc:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=g2PLacIMnXU:0NZqOv15ZNc:-BTjWOF_DHI" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=g2PLacIMnXU:0NZqOv15ZNc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=g2PLacIMnXU:0NZqOv15ZNc:F7zBnMyn0Lo" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=g2PLacIMnXU:0NZqOv15ZNc:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=g2PLacIMnXU:0NZqOv15ZNc:V_sGLiPBpWU" border="0" /></a>
</div><img src="http://feeds.feedburner.com/~r/PythonSoftwareFoundationNews/~4/g2PLacIMnXU" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/PythonSoftwareFoundationNews/~3/g2PLacIMnXU/2012-q1-community-service-awards.html]]></link>
    <pubDate>2012-05-24 10:30:04</pubDate>
  </item>
  <item>
    <title><![CDATA[Alex Clark: A simple printer of nested lists]]></title>
    <description><![CDATA[<p><em>A rant</em></p>
<p>Do you ever get the urge to kill? How many of us cringe whenever we see these words? Lately I&#8217;ve been spending a lot of time developing <a href="http://pythonpackages.com">pythonpackages.com</a>, (now running on heroku!) during which time I see a lot of these kinds of packages being released:</p>
<p><a href="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-9.41.32-PM.png"><img class="alignright size-full wp-image-4901" title="Screen Shot 2012-05-23 at 9.41.32 PM" src="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-9.41.32-PM.png" alt="" width="681" height="321" /></a></p>
<p>I kid about the killing part, but seriously: <strong>this is a problem</strong>. Fortunately for us, our PyPI overloads see fit to occasionally remove these packages, and for this I am grateful. I love seeing this:</p>
<p><a href="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-9.57.43-PM.png"><img class="alignright size-full wp-image-4905" title="Screen Shot 2012-05-23 at 9.57.43 PM" src="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-9.57.43-PM.png" alt="" width="1018" height="622" /></a></p>
<p>I mean it makes me <em>dance-around-the-room</em> happy! Ahem. But are they really all gone? Close enough. A quick <a href="https://crate.io/?q=a+simple+printer+of+nested+lists">crate.io search</a> now shows only 2 packages instead of 4 pages of results:</p>
<p><a href="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-10.04.46-PM.png"><img class="alignright size-full wp-image-4911" title="Screen Shot 2012-05-23 at 10.04.46 PM" src="http://blog.aclark.net/wp-content/uploads/2012/05/Screen-Shot-2012-05-23-at-10.04.46-PM.png" alt="" width="763" height="558" /></a></p>
<p>Hallelujah! But is this the best we can do? I know that some well-meaning person wrote a book containing the example that is leading some poor, misguided souls to spam PyPI (if only the author listed the test site instead: <a href="http://testpypi.python.org/pypi">http://testpypi.python.org/pypi</a>). And I have to assume that this was just some terrible mistake. But do we all have to live with this mistake?</p>
<p>I&#8217;m asking because I honestly don&#8217;t know the answer. I remember when I started pythonpackages.com, the <a href="http://pythonpackages.com/package/deliverance">Deliverance</a> documentation was being updated something like every 5 minutes (kidding again, but it was frequent enough to be annoying). After grousing about it in public, it stopped happening!</p>
<p>I wonder if some good natured grousing about our friends (read: enemies) the <em>simple printers of nested lists</em> will do the same?</p>
<img src="http://feeds.feedburner.com/~r/aclark/python/~4/qZ4IvG00EPs" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/aclark/python/~3/qZ4IvG00EPs/]]></link>
    <pubDate>2012-05-24 02:58:36</pubDate>
  </item>
  <item>
    <title><![CDATA[Mike Driscoll: My First Patch Was Accepted!]]></title>
    <description><![CDATA[<p>I&#8217;m a little excited today as my first patch (and first ticket even!) has been accepted. And it really didn&#8217;t take very long either. Less than 24 hours after I had submitted my first patch, I got my contribution added. I did have to submit to more variations of the patch though as my first one wasn&#8217;t quite right. I wanted to give a shout out to Brian Curtin and Eli Bendersky who helped me figure all this stuff out and made my first foray into core Python development a success. Personally, I think it would have been a success even if the patch wasn&#8217;t accepted as I still learned a lot along the way.</p>
<p>Things to take away from the experience:</p>
<ul>
<li>Try to stay on topic! I actually found a second issue with the paragraph I was fixing in the devguide and that probably should have gone in a separate bug report.</li>
<li>Number your patches! I don&#8217;t know why I didn&#8217;t think of that, but Eli told me I should do that in the future to make it less confusing for the committer. That was a face palm moment.</li>
</ul>
<p>I&#8217;ve been reading some of the supposedly &#8220;easy bugs&#8221; and trying to figure out where else I can help. I already spotted another typo in the docs that are included with Python itself which I&#8217;ll probably try to fix. Of course, I want to actually contribute to the code, not just the documentation, but I am probably more likely to be able to find documentation bugs I can help with. Hopefully with more experience I&#8217;ll be able to contribute more effectively. Happy hacking my fellow Pythoneers!</p>]]></description>
    <link><![CDATA[http://www.blog.pythonlibrary.org/2012/05/23/my-first-patch-was-accepted/]]></link>
    <pubDate>2012-05-24 00:29:02</pubDate>
  </item>
  <item>
    <title><![CDATA[Enthought: Just released! EPD 7.3 plus beta version of EPD 8.0]]></title>
    <description><![CDATA[Today we have for you not just one, but two exciting EPD releases &#8212; an update of EPD to 7.3 and a beta release previewing new features coming in EPD 8.0. The EPD 7.3 update adds several new packages including Shapely, openpyxl, and a new package from Enthought named EnaML.  EnaML is a new package for [...]]]></description>
    <link><![CDATA[http://blog.enthought.com/general/epd-73-and-8-beta/]]></link>
    <pubDate>2012-05-23 23:09:17</pubDate>
  </item>
  <item>
    <title><![CDATA[Python Software Foundation: Request for Proposal: Redesign python.org]]></title>
    <description><![CDATA[The main Python site at <a href="http://www.python.org/">www.python.org</a> was redesigned in 2005-2006 -- over six years ago.  It's time for a redesign, to improve the organization of the site and its appearance, and to simplify the task for the volunteers who maintain the content.  The PSF would therefore like fund the design and implementation of a new look and architecture for python.org.  The web development landscape has also changed a lot since 2006, and we look forward to seeing what this community can produce.<br />
<br />
The <a href="http://pythonorg-redesign.readthedocs.org/en/latest/index.html">Request for Proposal for the python.org redesign</a> has been published on readthedocs.org.  Questions and comments can be e-mailed to the psf-redesign mailing list at <a href="mailto:psf-redesign@python.org">psf-redesign at python.org</a>.  Proposals are due by July 21st 2012, two months from today.<br />
<br />
The RFP was initially drafted by Jesse Noller, and feedback from the python.org site maintainers was incorporated by Andrew Kuchling.<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/8520-5224525244093085722?l=pyfound.blogspot.com" alt="" /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=WBORCVywrHg:_paqNXBaExU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?d=yIl2AUoC8zA" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=WBORCVywrHg:_paqNXBaExU:-BTjWOF_DHI"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=WBORCVywrHg:_paqNXBaExU:-BTjWOF_DHI" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=WBORCVywrHg:_paqNXBaExU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=WBORCVywrHg:_paqNXBaExU:F7zBnMyn0Lo" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?a=WBORCVywrHg:_paqNXBaExU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/PythonSoftwareFoundationNews?i=WBORCVywrHg:_paqNXBaExU:V_sGLiPBpWU" border="0" /></a>
</div><img src="http://feeds.feedburner.com/~r/PythonSoftwareFoundationNews/~4/WBORCVywrHg" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/PythonSoftwareFoundationNews/~3/WBORCVywrHg/request-for-proposal-redesign-pythonorg.html]]></link>
    <pubDate>2012-05-23 17:21:37</pubDate>
  </item>
  <item>
    <title><![CDATA[Shannon -jj Behrens: Async: To Be or Not To Be]]></title>
    <description><![CDATA[<div dir="ltr"><p>Just because I have to use a callback-oriented style on the client doesn't mean I want to use a callback-oriented style on the server.  Now, before anyone gets all upset and tells me that I don't know the difference between async and a kitchen sink, let me explain :)</p> <p>The client is necessarily an event-oriented place.  If I don't know which button the user is going to press, it makes a lot of sense to use a different callback for each button.  The server is different.  If I'm waiting for the result of a database query before I can continue processing a request, it sure is convenient to just block and wait.</p> <p>My key point is that it's important to separate what <i>style</i> you want to code with and what <i>performance and scalability characteristics</i> you want.  You shouldn't necessarily pick a callback-oriented style just because you want the performance and scalability characteristics of asynchronous networking APIs.</p> <p>My favorite two examples are gevent and Erlang, but Go is similar.  When you code using gevent or Erlang, your code looks like synchronous, blocking code.  However, below the covers, they use asynchronous networking APIs.  Now, before anyone tells me that it's impossible, buggy, or that it'll never work, let me point out that these tricks have been in production for decades at Ericsson, Yahoo Groups, and IronPort Cisco.</p> <p>Furthermore, I should point out that asynchronous networking APIs aren't a perfect fit for every problem.  For instance, if your goal is to send 10 gigabytes of information to another server, it turns out that synchronous networking APIs will actually outperform asynchronous networking APIs.  The reason asynchronous networking APIs are so popular is because they can handle a larger number of clients than synchronous networking APIs can and because they use less memory than a large number of threads, which each have to have their own stack.  gevent and Erlang can handle a large number of clients, don't use up much memory, and don't require a real OS-level stack per client.</p> <p>So what's my problem with the callback-oriented style?  I find it a lot harder to read.  I've coded projects in Twisted, Node.js, etc., and I prefer the gevent approach.  You get roughly the same performance and scalability characteristics, but with much easier to read code.  Of course, what's readable to me may not be readable to other people.  I've met people who are perfectly happy using Twisted Web 1 and don't think that callback-oriented code poses any real challenge.</p> <p>If you're interested in hearing more about my thoughts on async and concurrency, check out <a href="http://jjinux.blogspot.com/search?q=gevent+OR+concurrency">my other blog posts</a>, which include a link to my Dr. Dobb's Journal article on Python concurrency.</p></div><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/11788780-2537509446612004035?l=jjinux.blogspot.com" alt="" /></div>]]></description>
    <link><![CDATA[http://jjinux.blogspot.com/2012/05/async-to-be-or-not-to-be.html]]></link>
    <pubDate>2012-05-23 16:42:01</pubDate>
  </item>
  <item>
    <title><![CDATA[Jesse Noller: Python.org Redesign Request For Proposals]]></title>
    <description><![CDATA[<p>Well, it’s official — a labor of love from myself and many others — with special thanks to Andrew Kuchling for getting it over the finish line. The Python Software Foundation has officially announced a call for proposals for the redesign of the Python.org site and properties.</p>
<p>You can see the RFP here: <a href="http://pythonorg-redesign.readthedocs.org/en/latest/">http://pythonorg-redesign.readthedocs.org/en/latest/</a></p>
<p>It’s taken me several years of false starts, other attempts (including skunkworks attempts), political and social discussions, and the hard work of many to make this come to fruition. Now, we can only sit back and hope that we see some amazing proposals from the community and others.</p>
<p>I sincerely hope this will be successful, and that we will see a modern, well designed Python.org that showcases not only the language, but the vibrant, open, welcoming and active community we are all part of. </p>
 <p><a href="http://jessenoller.com/?flattrss_redirect&id=1141&md5=21a56dfa5feea14a76d208e81b851ac1" title="Flattr" target="_blank"><img src="http://jessenoller.com/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!" /></a></p>]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/Jessenollercom/~3/CJ1qZlQS29E/]]></link>
    <pubDate>2012-05-23 12:42:35</pubDate>
  </item>
  <item>
    <title><![CDATA[Python Diary: Starting to like Web2Py]]></title>
    <description><![CDATA[<p>I am starting to enjoy working with <a href="http://www.pythondiary.com/packages/web2py.html">Web2py</a><a href="http://web2py.com/" rel="tooltip" title="Direct link"><i class="icon-bookmark"></i></a>.  I was recently provided with a review copy of a recent Web2Py book, and I have started reading through it.  I will have a full review of this book in the next couple weeks.  When I first went on to learn Web2Py, I used the free online book, and that for the most part didn't change me over.  The free online, like <a href="http://www.pythondiary.com/packages/django.html">Django</a><a href="https://www.djangoproject.com/" rel="tooltip" title="Direct link"><i class="icon-bookmark"></i></a>'s online book, is just that.  A free online book, and didn't provide me with enough knowledge and confidence to develop using the framework.  I got into Django using it's very extensive documentation website.</p>
<p>The book I am reviewing has many examples which can easily be applied to real-world web applications, which I praise.  As I have been reading through the book, I have also been playing around and exploring Web2Py in general.  It has some very interesting design choices and features.  It is definitely good for someone who can never remember what to import, as there is rarely any need to import anything in web2py, besides when you need to import a 3rd party Python module.  At first, this design choice caught me off guard, as in Python, I am used to explicitly importing my modules for use.  Web2Py includes it's technical reference with the application itself, in the form of <a href="http://www.pythondiary.com/packages/epydoc.html">Epydoc</a><a href="http://epydoc.sourceforge.net/" rel="tooltip" title="Direct link"><i class="icon-bookmark"></i></a>.  I am not terribly fond of this documentation format, but it is how I learned <a href="http://www.pythondiary.com/packages/pyjamas.html">Pyjamas</a><a href="http://pyjs.org/" rel="tooltip" title="Direct link"><i class="icon-bookmark"></i></a>, as it uses the same documentation system.</p>
<p>Web2Py has some interesting magic, which frankly does make web development a breeze.  Generating forms and cruds is literally a one-liner, further customization can be made by using more lines of code.  Web2Py also comes with a nice default template, and the application wizard, has many additional templates for use as well.  This feature is definitely well welcomed in my book.  Sure, it implies that tons of websites made with Web2Py will have the same look and feel, but is that such a bad thing?  It just means that visitors will know where most resources can be found, and how to use the included form widgets.  Think of Wordpress, most Wordpress sites I visit keep the included wordpress theme.  Blogspot is another example of a set of websites which share a common theme.  The included themes allow one to get to developing the website as quickly as possible without having to worry about how it will look and feel, but rather focus on the functionality.  I am more of a functionality person, not a look-and-feel type of person.</p>
<p>All in all, I am very excited to be trying out Web2Py for a second time, and do hope that when I complete this book, I can both provide a review of the book itself, as well as the framework in general.  Neither of these reviews will be compared to anything, and be strictly of the book and framework itself.  I am thinking of making a future website using Web2Py to see where it goes.  I will most likely keep my blog running on Django, as I have used many Django-specific features which would be otherwise troublesome to migrate over.  These articles contain Django template code, for example.</p>]]></description>
    <link><![CDATA[http://www.pythondiary.com/blog/May.23,2012/starting-web2py.html]]></link>
    <pubDate>2012-05-23 11:42:19</pubDate>
  </item>
  <item>
    <title><![CDATA[Daniel Greenfeld: Django Class Based View: email form with CAPTCHA]]></title>
    <description><![CDATA[<p><a class="reference external" href="http://pydanny.com/simple-django-email-form-using-cbv.html">Yesterday I showed how to implement a simple email form</a> for <a class="reference external" href="http://djangoproject.com">Django</a> using Class Based Views. Today I'm going to extend yesterday's work to use the excellent <a class="reference external" href="http://www.google.com/recaptcha">RECAPTCHA</a> service to help reduce spam content.</p>
<p>This version requires <tt class="docutils literal">pip</tt> installing the following into your <tt class="docutils literal">virtualenv</tt>.</p>
<ul class="simple">
<li><tt class="docutils literal">pip install <span class="pre">django-crispy-forms</span></tt> so we can do Python driven layouts.</li>
<li><tt class="docutils literal">pip install <span class="pre">django-floppyforms</span></tt> so we get HTML5 elements for free.</li>
<li><tt class="docutils literal">pip install <span class="pre">django-recaptcha</span></tt> to do the RECAPTCHA work.</li>
</ul>
<p>Don't forget to add the app to your INSTALLED_APPS in settings.py:</p>
<div class="highlight"><pre><span class="n">INSTALLED_APPS</span> <span class="o">+=</span> <span class="p">(</span>
    <span class="s">'crispy_forms'</span><span class="p">,</span>
    <span class="s">'floppyforms'</span><span class="p">,</span>
    <span class="s">'captcha'</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>Generate your KEYs from the RECAPTCHA site and add them in settings.py:</p>
<div class="highlight"><pre><span class="n">RECAPTCHA_PUBLIC_KEY</span> <span class="o">=</span> <span class="s">'6LcVu9ESAAAAANVWwbM5-PLuLES94GQ2bIYmSNTG'</span>
<span class="n">RECAPTCHA_PRIVATE_KEY</span> <span class="o">=</span> <span class="s">'6LcVu9ESAAAAAGxz7aEIACWRa3CVnXN3mFd-cajP'</span>
</pre></div>
<p>In myapp.forms.py:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">captcha.fields</span> <span class="kn">import</span> <span class="n">ReCaptchaField</span>  <span class="c"># Only import different from yesterday</span>
<span class="kn">from</span> <span class="nn">crispy_forms.helper</span> <span class="kn">import</span> <span class="n">FormHelper</span>
<span class="kn">from</span> <span class="nn">crispy_forms.layout</span> <span class="kn">import</span> <span class="n">Submit</span>
<span class="kn">import</span> <span class="nn">floppyforms</span> <span class="kn">as</span> <span class="nn">forms</span>

<span class="k">class</span> <span class="nc">ContactForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>

    <span class="n">name</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">email</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">EmailField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">subject</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">message</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">Textarea</span><span class="p">)</span>
    <span class="n">captcha</span> <span class="o">=</span> <span class="n">ReCaptchaField</span><span class="p">()</span>  <span class="c"># Only field different from yesterday</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">helper</span> <span class="o">=</span> <span class="n">FormHelper</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">helper</span><span class="o">.</span><span class="n">add_input</span><span class="p">(</span><span class="n">Submit</span><span class="p">(</span><span class="s">'submit'</span><span class="p">,</span> <span class="s">'Submit'</span><span class="p">))</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">ContactForm</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
<p>In myapp.views.py:</p>
<div class="highlight"><pre><span class="c"># Unchanged from yesterday. :-)</span>
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.core.mail</span> <span class="kn">import</span> <span class="n">send_mail</span>
<span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">FormView</span>

<span class="kn">from</span> <span class="nn">myapp.forms</span> <span class="kn">import</span> <span class="n">ContactForm</span>

<span class="k">class</span> <span class="nc">ContactFormView</span><span class="p">(</span><span class="n">FormView</span><span class="p">):</span>

    <span class="n">form_class</span> <span class="o">=</span> <span class="n">ContactForm</span>
    <span class="n">template_name</span> <span class="o">=</span> <span class="s">&quot;myapp/email_form.html&quot;</span>
    <span class="n">success_url</span> <span class="o">=</span> <span class="s">'/email-sent/'</span>

    <span class="k">def</span> <span class="nf">form_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">form</span><span class="p">):</span>
        <span class="n">message</span> <span class="o">=</span> <span class="s">&quot;{name} / {email} said: &quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
            <span class="n">name</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'name'</span><span class="p">),</span>
            <span class="n">email</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'email'</span><span class="p">))</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="s">&quot;</span><span class="se">\n\n</span><span class="s">{0}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'message'</span><span class="p">))</span>
        <span class="n">send_mail</span><span class="p">(</span>
            <span class="n">subject</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'subject'</span><span class="p">),</span>
            <span class="n">message</span><span class="o">=</span><span class="n">message</span><span class="p">,</span>
            <span class="n">from_email</span><span class="o">=</span><span class="s">'contact-form@myapp.com'</span><span class="p">,</span>
            <span class="n">recipient_list</span><span class="o">=</span><span class="p">[</span><span class="n">settings</span><span class="o">.</span><span class="n">LIST_OF_EMAIL_RECIPIENTS</span><span class="p">],</span>
        <span class="p">)</span>
        <span class="k">return</span> <span class="nb">super</span><span class="p">(</span><span class="n">ContactFormView</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">form_valid</span><span class="p">(</span><span class="n">form</span><span class="p">)</span>
</pre></div>
<p>In templates/myapp/email_form.html:</p>
<div class="highlight"><pre>{# Also unchanged from yesterday. :-)  #}
{% extends 'base.html' %}
{% load crispy_forms_tags %}

{% block title %}Send an email{% endblock %}

{% block content %}
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;row&quot;</span><span class="nt">&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;span6&quot;</span><span class="nt">&gt;</span>
            <span class="nt">&lt;h1&gt;</span>Send an email<span class="nt">&lt;/h1&gt;</span>
            {% crispy form form.helper %}
        <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
{% endblock %}

{% block extrajs %}
<span class="nt">&lt;script </span><span class="na">src=</span><span class="s">&quot;{{ STATIC_URL }}js/jquery-1.7.1.min.js&quot;</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">&quot;text/javascript&quot;</span><span class="nt">&gt;</span>
<span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">$</span><span class="p">(</span><span class="s1">'#id_name'</span><span class="p">).</span><span class="nx">focus</span><span class="p">()</span>
<span class="p">});</span>
<span class="nt">&lt;/script&gt;</span>
{% endblock %}
</pre></div>
<div class="section" id="what-i-did">
<h2>What I did</h2>
<ul class="simple">
<li>Using <tt class="docutils literal">pip</tt> I installed three packages into my Python environment.</li>
<li>Added those three packages into the INSTALLED_APPS setting.</li>
<li>Set the RECAPTCHA keys for my site.</li>
<li>Modified the <tt class="docutils literal">forms.py</tt> file from yesterday to include the RECAPTCHA field.</li>
<li>Reduced spam content.</li>
</ul>
</div>
<div class="section" id="what-i-could-do">
<h2>What I could do</h2>
<ul class="simple">
<li>Pin the app versions for a particular release. This is what you should be doing in normal development and in production, but for a blog entry I'm avoiding it because release numbers become quickly dated.</li>
<li>Rather than change the <tt class="docutils literal">ContactForm</tt> from yesterday, I could have extended it via inheritance.</li>
</ul>
</div>
<div class="section" id="want-to-learn-more">
<h2>Want to learn more?</h2>
<p>If you live in the Los Angeles area and want to learn more about Django, everything from the basics to setting up a Content Management System or E-Commerce system, check out our Django (and <a class="reference external" href="http://python.org">Python</a>) training at <a class="reference external" href="https://academy.cartwheelweb.com">Cartwheel Academy</a>.</p>
</div>]]></description>
    <link><![CDATA[http://pydanny.com/django-class-based-view-email-form-with-captcha.html]]></link>
    <pubDate>2012-05-23 09:30:00</pubDate>
  </item>
  <item>
    <title><![CDATA[Mike Driscoll: Core Python Development: How to Submit a Patch]]></title>
    <description><![CDATA[<p>As I mentioned in my last article, I figured I&#8217;d try to find something that I could patch in Python and submit it. While writing the other article, I stumbled on a minor error in the Python devguide in the <a href="http://docs.python.org/devguide/setup.html#windows" target="_blank">Windows section</a>. While it&#8217;s nowhere near as cool to patch a piece of documentation as I think it would be to patch Python, I think it&#8217;s rather appropriate for me as I tend to contribute more documentation than anything else lately. So I am going to explain the process as I found it.<span id="more-2343"></span></p>
<h3>Getting Started</h3>
<p>First off, you need to get an account with the <a href="http://bugs.python.org/" target="_blank">Bug Tracker</a> for Python. If you hope to become a core developer, then you&#8217;ll need to make sure your username follows their guidelines, which are really simple:</p>
<p><code><br />
firstname.lastname<br />
</code></p>
<p>Once you&#8217;ve got that, you can start looking for something to patch. There&#8217;s a link that says &#8220;Easy issues&#8221; that is a good starting place. You can also do a search for a component that you&#8217;re competent in using and see if there are any bugs in there that you think you can fix. Once you find something, you&#8217;ll need to make sure you update your local repo and then read the devguide&#8217;s <a href="http://docs.python.org/devguide/patch.html" target="_blank">patch page</a>.</p>
<h3>Creating the Patch</h3>
<p>Assuming you have the necessary repository checked out on your local machine, all you need to do is go edit the appropriate file. In my case, I had to check out the devguide (which you can read about <a href="http://docs.python.org/devguide/" target="_blank">here</a>) and edit the <strong>setup.rst</strong> file. If you&#8217;re editing Python code, then you&#8217;ll have to conform to PEP8. Once I finished editing the file, I saved my changes and then had to use Mercurial to create the patch. Here&#8217;s the command I used per the Python<a href="http://docs.python.org/devguide/patch.html" target="_blank"> patch instructions</a>.</p>
<p><code><br />
hg diff &gt; setup.patch<br />
</code></p>
<p>And here is the contents of that patch file:</p>
<p><code><br />
diff -r b1c1d15271c0 setup.rst<br />
--- a/setup.rst	Tue May 22 00:33:42 2012 +0200<br />
+++ b/setup.rst	Tue May 22 13:55:09 2012 -0500<br />
@@ -173,7 +173,7 @@<br />
 To build from the Visual Studio GUI, open pcbuild.sln to load the project<br />
 files and choose the Build Solution option from the Build menu, often<br />
 associated with the F7 key. Make sure you have chosen the &quot;Debug&quot; option from<br />
-the build configuration drop-down first.<br />
+the configuration toolbar drop-down first.</code></p>
<p> Once built you might want to set Python as a startup project. Pressing F5 in<br />
 Visual Studio, or choosing Start Debugging from the Debug menu, will launch<br />
</p>
<p>Now that we have a patch we need to submit it!</p>
<h3>Submitting a Patch</h3>
<p>Put your shields up, we&#8217;re going in! Submitting a patch is a little daunting. What will people think of you? I suspect if you plan to work on something major, then you better start growing some thick skin. In my case, I&#8217;m going to submit a really simple typo fix, so I&#8217;m hoping that sort of thing isn&#8217;t flame-worthy. Then again, this is my first patch, so I may submit it in a completely erroneous way. Since my patch will be for something (presumably) new, I did a quick search to make sure it hadn&#8217;t already been reported. Seeing nothing, I clicked the &#8220;Create New&#8221; link with some trepidation and choose the &#8220;devguide&#8221; as my component. I also chose the latest version of Python. I don&#8217;t see anything in the devguide that says it applies to just one set of Python versions, so I&#8217;m just going to leave it at that. I didn&#8217;t really see a &#8220;type&#8221; that fit a devguide edit, so I left that blank for my betters to fix. Finally, I attached my patch file to the bug ticket. You can see my bug ticket <a href="http://bugs.python.org/issue14884">here</a> if you like.</p>
<p>When contributing a patch to Python, you should fill out a <a href="http://www.python.org/psf/contrib/" target="_blank">contributor agreement form</a> which allows the Python Software Foundation to license your code for use with Python while you get to keep the copyright. Yes, you too can become famous just for writing Python code! Assuming people read the source or those acknowledgement pages. </p>
<h3>Wrapping Up</h3>
<p>I don&#8217;t know what will happen to my rather lame contribution. Maybe it&#8217;ll get accepted, maybe not. But I think I&#8217;ll spend some time trying to figure out some other bugs and just see if there&#8217;s anything I can do to help out the Python community. Feel free to join me on this adventure!</p>]]></description>
    <link><![CDATA[http://www.blog.pythonlibrary.org/2012/05/22/core-python-development-how-to-submit-a-patch/]]></link>
    <pubDate>2012-05-22 23:22:07</pubDate>
  </item>
  <item>
    <title><![CDATA[Mikko Ohtamaa: Automatically colorize terminal tabs based on the server you are logged into]]></title>
    <description><![CDATA[<p>Behold:</p>
<p><img class="alignnone" title="Colorized tabs example scerenshot" src="https://github.com/downloads/miohtama/ztanesh/Screen%20Shot%202012-05-22%20at%2011.01.46%20PM.png" alt="" width="670" height="329" /></p>
<p>OSX&#8217;s <a href="http://opensourcehacker.com/category/python/feed/www.iterm2.com">iTerm 2</a>, and maybe some other terminal applications, support <a href="http://en.wikipedia.org/wiki/ANSI_escape_code">ANSI control sequence</a> extensions which allow shell to set the color of the terminal tab.</p>
<p>Below is a Python script which</p>
<ul>
<li>Randomizes a color based on the server host name. The same hostname always results to the same color.</li>
<li>The color is randomized in HSL color space, so that only the hue component varies and saturation and lightness are locked. This prevents the creation of ugly color combinations like black text on black tab background.</li>
</ul>
<p><em>Note: The effect can be also applied on terminal windows  &#8211; for those who don&#8217;t use tabs.</em></p>
<p>The effective result is that</p>
<ul>
<li>You learn to identify terminal tabs by the color</li>
<li>You can much more faster to switch between tabs, because you can visually pick up the terminal without needing to be able to read the text on it or remember its location in the list</li>
</ul>
<p><em>Note: If your puny terminal does not support setting the color of window decorations, you can always set the terminal background color. This is useful e.g. if you want to red background for <a href="http://www.youtube.com/watch?v=siwpn14IE7E&ob=av3n&noredirect=1">danger zone &#8482;</a> when you are logged in as root on the production server 23:00 Friday night.</em></p>
<p><em>Note: Naturally you also need to have the script installed on the servers you are ssh&#8217;ing into</em></p>
<h2>precmd() hook</h2>
<p>You can run the script once and the tab color is set. However, if you SSH from the computer to another  and then exit back, the color of the latest server would remain in this case.</p>
<p>This can be avoided by</p>
<ol>
<li>Calculating the OSC control code sequence needed to set the terminal tab color when the shell starts</li>
<li>Have a <em>precmd()</em> hook (zsh terminology, not sure what other shells use) to reset the tab color every time the shell prompt is displayd</li>
</ol>
<p>We, me with my friend, are maintaining (yet another) zsh toolkit called <a href="https://github.com/miohtama/ztanesh">ztanesh (github)</a>. There  you can find precmd() example codes in 1) <a href="https://github.com/miohtama/ztanesh/blob/master/zsh-scripts/rc/98-server-color">98-server-color</a> and 2) <a href="https://github.com/miohtama/ztanesh/blob/master/zsh-scripts/rc/99-prompt">80-statusbar</a>.</p>
<h2>rainbow-parade.py</h2>
<p><a href="https://github.com/miohtama/ztanesh/blob/master/zsh-scripts/bin/rainbow-parade.py">The script code lives on Github</a>. Currently it supports iTerm 2 only and we plan to expand support to Konsole. Patches for other terminals are welcome.</p>
<p>(This probably could be done in pure shell code too, but Python is just so much more fun&#8230;)</p>
<pre class="prettyprint lang-py">#!/usr/bin/env python
"""

       Set terminal tab / decoration color by the server name.

       Get a random colour which matches the server name and use it for the tab colour:
       the benefit is that each server gets a distinct color which you do not need
       to configure beforehand.

"""

import socket
import random
import colorsys
import sys

# http://stackoverflow.com/questions/1523427/python-what-is-the-common-header-format
__copyright__ = "Copyright 2012 Mikko Ohtamaa - http://opensourcehacker.com"
__author__ = "Mikko Ohtamaa &lt;mikko@opensourcehacker.com&gt;"
__licence__ = "WTFPL"
__credits__ = ["Antti Haapala"]

USAGE = """
Colorize terminal tab based on the current host name.

Usage: rainbow-parade.py [0-1.0] [0-1.0] # Lightness and saturation values

An iTerm 2 example (recolorize dark grey background and black text):

    rainbow-parade.py 0.7 0.4
"""

def get_random_by_string(s):
    """
    Get always the same 0...1 random number based on an arbitrary string
    """

    # Initialize random gen by server name hash
    random.seed(s)
    return random.random()

def decorate_terminal(color):
    """
    Set terminal tab / decoration color.

    Please note that iTerm 2 / Konsole have different control codes over this.
    Note sure what other terminals support this behavior.

    :param color: tuple of (r, g, b)
    """

    r, g, b = color

    # iTerm 2
    # http://www.iterm2.com/#/section/documentation/escape_codes"
    sys.stdout.write("\033]6;1;bg;red;brightness;%d\a" % int(r * 255))
    sys.stdout.write("\033]6;1;bg;green;brightness;%d\a" % int(g * 255))
    sys.stdout.write("\033]6;1;bg;blue;brightness;%d\a" % int(b * 255))
    sys.stdout.flush()

    # Konsole
    # TODO
    # http://meta.ath0.com/2006/05/24/unix-shell-games-with-kde/

def rainbow_unicorn(lightness, saturation):
    """
    Colorize terminal tab by your server name.

    Create a color in HSL space where lightness and saturation is locked, tune only hue by the server.

    http://games.adultswim.com/robot-unicorn-attack-twitchy-online-game.html
    """

    name = socket.gethostname()

    hue = get_random_by_string(name)

    color = colorsys.hls_to_rgb(hue, lightness, saturation)

    decorate_terminal(color)

def main():
    """
    From Toholampi with love http://www.toholampi.fi/tiedostot/119_yleisesite_englanti_naytto.pdf
    """
    if(len(sys.argv) &lt; 3):
        sys.exit(USAGE)

    lightness = float(sys.argv[1])
    saturation = float(sys.argv[2])

    rainbow_unicorn(lightness, saturation)

if __name__ == "__main__":
    main()</pre>
<p class="signature">
 <a href="http://feeds.feedburner.com/mFabrikWebAndMobileDevelopment" rel="alternate" type="application/rss+xml"><img valign="middle" src="http://www.feedburner.com/fb/images/pub/feed-icon16x16.png" alt="" /></a> <a href="http://feeds.feedburner.com/OpenSourceHacker" rel="alternate" type="application/rss+xml">Subscribe to this blog in a reader</a> <a href="http://twitter.com/moo9000"> <img valign="middle" src="http://opensourcehacker.com/wp-content/uploads/twitter-24.png" /></a> <a href="http://twitter.com/moo9000">Follow me on Twitter</a> </p>]]></description>
    <link><![CDATA[http://opensourcehacker.com/2012/05/22/automatically-colorize-terminal-tabs-based-on-the-server-you-are-logged-into/]]></link>
    <pubDate>2012-05-22 20:35:50</pubDate>
  </item>
  <item>
    <title><![CDATA[Simeon Franklin: What Generators are for]]></title>
    <description><![CDATA[<p>I teach Python classes and enjoy exploring language features from the
perspective of newbie's to the language. Usually I can explain the
rationale for Python language features by showing a compelling use
case. But what about generator functions?</p>


<a href="http://simeonfranklin.com/blog/2012/may/22/what-generators-are-for/">Read More</a>]]></description>
    <link><![CDATA[http://simeonfranklin.com/blog/2012/may/22/what-generators-are-for/]]></link>
    <pubDate>2012-05-22 17:57:51</pubDate>
  </item>
  <item>
    <title><![CDATA[Nick Coghlan: An embarrassment of riches]]></title>
    <description><![CDATA[Years ago (but still within the last decade) I was involved in a source control trade study for a large multi-national corporation. Management had let a non-software developer select the original "source control tool" and they had picked something that required custom scripting just to do a baseline (I wish I was kidding).<br /><br />So a bunch of candidate replacements were put forward for consideration, and CVS won because it was free, thus there would be fewer arguments with management about rolling it out on a project that was already over budget and behind schedule. (The fact that Subversion wasn't considered as a candidate should give you some additional hints about the precise timing of this - Subversion 1.0 was released in February 2004. Yes, for those that are new to this game, you read that right: it is only within the last decade that the majority of the open source VCS world began to enjoy the benefits of atomic commits).<br /><br />Other interesting aspects of that system included the fact that one of the developers on that project basically had to write a custom xUnit testing system from scratch in order to start putting together a decent automated test suite for the system, there was no code review tool, and you couldn't include direct links to bug tracker items in emails or anything else - you had to reference them by name or number, and people would then look those names or numbers up in the dedicated bug tracking application client.<br /><br />High level design documentation, if it existed at all, was in the form of Microsoft Word documents. Low level API documentation? Yes, that would have been nice (there were some attempts to generate something vaguely readable with Doxygen but, yeah, well, C++).<br /><br />Less than ten years later, though, and there are signs our industry is starting to grow up (although I expect many enterprise shops are still paying extortionate rates to the likes of IBM for the "Rational" suite of tools only to gain a significantly inferior development experience):<br /><ol><li>You can get genuinely high quality code hosting for free. Sure <a href="http://sourceforge.net/">Sourceforge</a> was already around back then, but Git and Mercurial stomp all over CVS from a collaboration point of view. These also come with decent issue trackers and various other collaboration tools. If you don't want to trust a service provider with your code, than tools like <a href="http://gitlabhq.com/">GitLab</a> let you set up similar environments internally.</li><li>Web based issue trackers are everywhere, with the ubiquitous "issue URL" allowing effective cross-linking between tracker issues, documentation, code comments, source control browsers, code review systems, etc.</li><li>Dedicated code review tools like <a href="https://code.google.com/p/gerrit/">Gerrit</a> and <a href="https://code.google.com/p/rietveld/">Reitveld</a> are published as open source (and, in the case of the latter, even available as a free service on <a href="http://codereview.appspot.com/">Google App Engine</a>).</li><li>Services like <a href="http://readthedocs.org/">ReadTheDocs</a> exist, allowing you to easily build and publish high quality documentation. All with nice URLs so you can link it from emails, tracker issues, source code, etc.</li><li>Organisations like <a href="https://www.shiningpanda.com/">Shining Panda CI</a> and <a href="http://travis-ci.org/">Travis CI</a> provide hosted continuous integration services that put the internal capabilities of many large companies to shame.</li><li>Language communities provide cross-platform distribution services to reach a global audience.</li><li>Depending on the language you use, you may even have tools like <a href="http://www.sonarsource.org/">SonarSource</a> available</li><li>Once you go into production in the web application world, service components like <a href="https://www.getsentry.com/welcome/">Sentry</a>, <a href="http://piwik.org/">Piwik</a>, and <a href="http://graphite.wikidot.com/faq">Graphite</a> are again available for no charge.</li></ol>And to access all this good stuff for free? All you have to do is be willing to share your work (and sometimes not even that). If you don't want to share your work, then the service providers generally have very reasonable fees - you could probably put together a state of the art suite of tools for less than a few hundred bucks a month.<br /><br />Take my own hobby projects as an example:<br /><ul><li>they're hosted on <a href="https://bitbucket.org/ncoghlan/">BitBucket</a> as Mercurial projects (I happen to prefer Mercurial, although I can definitely see why people like Git, too). That gives me integrated issue tracking and online source code browsing, too. (OK, so I could have had essentially that back in the early SourceForge days, but the UI aspects have improved in many respects in the intervening years)</li><li>I can publish my projects on the <a href="http://pypi.python.org/">Python Package Index</a> with a simple "<span>setup.py sdist upload</span>". They're then available for anyone in the world to install with a straightforward command like "<span>pip install walkdir</span>"</li><li>thanks to <a href="https://jenkins.shiningpanda.com/ncoghlan-devs-projects/">Shining Panda CI</a>, I know the downloads from PyPI work, and I also know that the projects work on all the versions and implementations of Python I want to support</li><li>thanks to <a href="http://readthedocs.org/profiles/ncoghlan/">ReadTheDocs</a> and <a href="http://sphinx.pocoo.org/">Sphinx</a>, you can read nicely formatted documentation like <a href="http://walkdir.readthedocs.org/">this</a> rather than trying to decipher plain text files or wiki pages.</li></ul>I'm living in the future and it is seriously <i>cool</i> (and that's just looking at things purely from a software development infrastructure point of view - the rise of "Infrastructure as a Service" and "Platform as a Service" providers, including Red Hat's own <a href="https://openshift.redhat.com/">OpenShift</a>, has massive implications on the deployment side of things, and there's of course the implications of the many open source wheels that don't need to be reinvented)<br /><br />The best part from my point of view is that these days I get to work for a <a href="http://www.redhat.com/">company</a> that already genuinely understands the long term significance of the power of collaborative development. It also doesn't hurt that there's still a lot of money to be made in helping the rest of the enterprise world come to grips with that reality :)<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/9320223-9142212041564052598?l=www.boredomandlaziness.org" alt="" /></div>]]></description>
    <link><![CDATA[http://www.boredomandlaziness.org/2012/05/embarrassment-of-riches.html]]></link>
    <pubDate>2012-05-22 17:40:34</pubDate>
  </item>
  <item>
    <title><![CDATA[Bryce Verdier: Project Euler: Problem 13]]></title>
    <description><![CDATA[<p>Problem thirteen from Project Euler is one of those problems that's so simple, I don't understand why it's in the double digits section. The problem reads: “Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.”<br />
It then proceeds to list 100 long numbers. I'm not going to paste them here because they are in the code solutions below and I don't want to clog up the <a href="http://lolcats.icanhascheezburger.com/2011/04/05/funny-pictures-the-internet-is-a-series-of-tubes/">“tubez”</a> with more redundant information than I'm about to.</p>
<p>Enough of my jibber-jabber.  Here is my Haskell solution first (trying to change things up here):<br />
<div class="geshifilter"><pre class="haskell geshifilter-haskell"><ol><li><div><span>module</span> Main <span>where</span></div></li><li><div>&nbsp;</div></li><li><div>main <span>::</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:IO"><span>IO</span></a><span>&#40;</span><span>&#41;</span></div></li><li><div>main <span>=</span> <span>do</span></div></li><li><div>    <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:print"><span>print</span></a> <span>.</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:take"><span>take</span></a> <span>10</span> <span>.</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:show"><span>show</span></a> <span>$</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:sum"><span>sum</span></a> big<span>_</span>number</div></li><li><div>    <span>where</span> big<span>_</span>number <span>=</span> <span>&#91;</span> <span>37107287533902102798797998220837590246510135740250</span></div></li><li><div>                       <span>,</span> <span>46376937677490009712648124896970078050417018260538</span></div></li><li><div>                       <span>,</span> <span>74324986199524741059474233309513058123726617309629</span></div></li><li><div>                       <span>,</span> <span>91942213363574161572522430563301811072406154908250</span></div></li><li><div>                       <span>,</span> <span>23067588207539346171171980310421047513778063246676</span></div></li><li><div>                       <span>,</span> <span>89261670696623633820136378418383684178734361726757</span></div></li><li><div>                       <span>,</span> <span>28112879812849979408065481931592621691275889832738</span></div></li><li><div>                       <span>,</span> <span>44274228917432520321923589422876796487670272189318</span></div></li><li><div>                       <span>,</span> <span>47451445736001306439091167216856844588711603153276</span></div></li><li><div>                       <span>,</span> <span>70386486105843025439939619828917593665686757934951</span></div></li><li><div>                       <span>,</span> <span>62176457141856560629502157223196586755079324193331</span></div></li><li><div>                       <span>,</span> <span>64906352462741904929101432445813822663347944758178</span></div></li><li><div>                       <span>,</span> <span>92575867718337217661963751590579239728245598838407</span></div></li><li><div>                       <span>,</span> <span>58203565325359399008402633568948830189458628227828</span></div></li><li><div>                       <span>,</span> <span>80181199384826282014278194139940567587151170094390</span></div></li><li><div>                       <span>,</span> <span>35398664372827112653829987240784473053190104293586</span></div></li><li><div>                       <span>,</span> <span>86515506006295864861532075273371959191420517255829</span></div></li><li><div>                       <span>,</span> <span>71693888707715466499115593487603532921714970056938</span></div></li><li><div>                       <span>,</span> <span>54370070576826684624621495650076471787294438377604</span></div></li><li><div>                       <span>,</span> <span>53282654108756828443191190634694037855217779295145</span></div></li><li><div>                       <span>,</span> <span>36123272525000296071075082563815656710885258350721</span></div></li><li><div>                       <span>,</span> <span>45876576172410976447339110607218265236877223636045</span></div></li><li><div>                       <span>,</span> <span>17423706905851860660448207621209813287860733969412</span></div></li><li><div>                       <span>,</span> <span>81142660418086830619328460811191061556940512689692</span></div></li><li><div>                       <span>,</span> <span>51934325451728388641918047049293215058642563049483</span></div></li><li><div>                       <span>,</span> <span>62467221648435076201727918039944693004732956340691</span></div></li><li><div>                       <span>,</span> <span>15732444386908125794514089057706229429197107928209</span></div></li><li><div>                       <span>,</span> <span>55037687525678773091862540744969844508330393682126</span></div></li><li><div>                       <span>,</span> <span>18336384825330154686196124348767681297534375946515</span></div></li><li><div>                       <span>,</span> <span>80386287592878490201521685554828717201219257766954</span></div></li><li><div>                       <span>,</span> <span>78182833757993103614740356856449095527097864797581</span></div></li><li><div>                       <span>,</span> <span>16726320100436897842553539920931837441497806860984</span></div></li><li><div>                       <span>,</span> <span>48403098129077791799088218795327364475675590848030</span></div></li><li><div>                       <span>,</span> <span>87086987551392711854517078544161852424320693150332</span></div></li><li><div>                       <span>,</span> <span>59959406895756536782107074926966537676326235447210</span></div></li><li><div>                       <span>,</span> <span>69793950679652694742597709739166693763042633987085</span></div></li><li><div>                       <span>,</span> <span>41052684708299085211399427365734116182760315001271</span></div></li><li><div>                       <span>,</span> <span>65378607361501080857009149939512557028198746004375</span></div></li><li><div>                       <span>,</span> <span>35829035317434717326932123578154982629742552737307</span></div></li><li><div>                       <span>,</span> <span>94953759765105305946966067683156574377167401875275</span></div></li><li><div>                       <span>,</span> <span>88902802571733229619176668713819931811048770190271</span></div></li><li><div>                       <span>,</span> <span>25267680276078003013678680992525463401061632866526</span></div></li><li><div>                       <span>,</span> <span>36270218540497705585629946580636237993140746255962</span></div></li><li><div>                       <span>,</span> <span>24074486908231174977792365466257246923322810917141</span></div></li><li><div>                       <span>,</span> <span>91430288197103288597806669760892938638285025333403</span></div></li><li><div>                       <span>,</span> <span>34413065578016127815921815005561868836468420090470</span></div></li><li><div>                       <span>,</span> <span>23053081172816430487623791969842487255036638784583</span></div></li><li><div>                       <span>,</span> <span>11487696932154902810424020138335124462181441773470</span></div></li><li><div>                       <span>,</span> <span>63783299490636259666498587618221225225512486764533</span></div></li><li><div>                       <span>,</span> <span>67720186971698544312419572409913959008952310058822</span></div></li><li><div>                       <span>,</span> <span>95548255300263520781532296796249481641953868218774</span></div></li><li><div>                       <span>,</span> <span>76085327132285723110424803456124867697064507995236</span></div></li><li><div>                       <span>,</span> <span>37774242535411291684276865538926205024910326572967</span></div></li><li><div>                       <span>,</span> <span>23701913275725675285653248258265463092207058596522</span></div></li><li><div>                       <span>,</span> <span>29798860272258331913126375147341994889534765745501</span></div></li><li><div>                       <span>,</span> <span>18495701454879288984856827726077713721403798879715</span></div></li><li><div>                       <span>,</span> <span>38298203783031473527721580348144513491373226651381</span></div></li><li><div>                       <span>,</span> <span>34829543829199918180278916522431027392251122869539</span></div></li><li><div>                       <span>,</span> <span>40957953066405232632538044100059654939159879593635</span></div></li><li><div>                       <span>,</span> <span>29746152185502371307642255121183693803580388584903</span></div></li><li><div>                       <span>,</span> <span>41698116222072977186158236678424689157993532961922</span></div></li><li><div>                       <span>,</span> <span>62467957194401269043877107275048102390895523597457</span></div></li><li><div>                       <span>,</span> <span>23189706772547915061505504953922979530901129967519</span></div></li><li><div>                       <span>,</span> <span>86188088225875314529584099251203829009407770775672</span></div></li><li><div>                       <span>,</span> <span>11306739708304724483816533873502340845647058077308</span></div></li><li><div>                       <span>,</span> <span>82959174767140363198008187129011875491310547126581</span></div></li><li><div>                       <span>,</span> <span>97623331044818386269515456334926366572897563400500</span></div></li><li><div>                       <span>,</span> <span>42846280183517070527831839425882145521227251250327</span></div></li><li><div>                       <span>,</span> <span>55121603546981200581762165212827652751691296897789</span></div></li><li><div>                       <span>,</span> <span>32238195734329339946437501907836945765883352399886</span></div></li><li><div>                       <span>,</span> <span>75506164965184775180738168837861091527357929701337</span></div></li><li><div>                       <span>,</span> <span>62177842752192623401942399639168044983993173312731</span></div></li><li><div>                       <span>,</span> <span>32924185707147349566916674687634660915035914677504</span></div></li><li><div>                       <span>,</span> <span>99518671430235219628894890102423325116913619626622</span></div></li><li><div>                       <span>,</span> <span>73267460800591547471830798392868535206946944540724</span></div></li><li><div>                       <span>,</span> <span>76841822524674417161514036427982273348055556214818</span></div></li><li><div>                       <span>,</span> <span>97142617910342598647204516893989422179826088076852</span></div></li><li><div>                       <span>,</span> <span>87783646182799346313767754307809363333018982642090</span></div></li><li><div>                       <span>,</span> <span>10848802521674670883215120185883543223812876952786</span></div></li><li><div>                       <span>,</span> <span>71329612474782464538636993009049310363619763878039</span></div></li><li><div>                       <span>,</span> <span>62184073572399794223406235393808339651327408011116</span></div></li><li><div>                       <span>,</span> <span>66627891981488087797941876876144230030984490851411</span></div></li><li><div>                       <span>,</span> <span>60661826293682836764744779239180335110989069790714</span></div></li><li><div>                       <span>,</span> <span>85786944089552990653640447425576083659976645795096</span></div></li><li><div>                       <span>,</span> <span>66024396409905389607120198219976047599490197230297</span></div></li><li><div>                       <span>,</span> <span>64913982680032973156037120041377903785566085089252</span></div></li><li><div>                       <span>,</span> <span>16730939319872750275468906903707539413042652315011</span></div></li><li><div>                       <span>,</span> <span>94809377245048795150954100921645863754710598436791</span></div></li><li><div>                       <span>,</span> <span>78639167021187492431995700641917969777599028300699</span></div></li><li><div>                       <span>,</span> <span>15368713711936614952811305876380278410754449733078</span></div></li><li><div>                       <span>,</span> <span>40789923115535562561142322423255033685442488917353</span></div></li><li><div>                       <span>,</span> <span>44889911501440648020369068063960672322193204149535</span></div></li><li><div>                       <span>,</span> <span>41503128880339536053299340368006977710650566631954</span></div></li><li><div>                       <span>,</span> <span>81234880673210146739058568557934581403627822703280</span></div></li><li><div>                       <span>,</span> <span>82616570773948327592232845941706525094512325230608</span></div></li><li><div>                       <span>,</span> <span>22918802058777319719839450180888072429661980811197</span></div></li><li><div>                       <span>,</span> <span>77158542502016545090413245809786882778948721859617</span></div></li><li><div>                       <span>,</span> <span>72107838435069186155435662884062257473692284509516</span></div></li><li><div>                       <span>,</span> <span>20849603980134001723930671666823555245252804609722</span></div></li><li><div>                       <span>,</span> <span>53503534226472524250874054075591789781264330331690</span><span>&#93;</span></div></li></ol></pre></div></p>
<p>followed by my Python solution:<br />
<div class="geshifilter"><pre class="python geshifilter-python"><ol><li><div><span>#!/usr/bin/python</span></div></li><li><div><span>&quot;&quot;&quot;</span></div></li><li><div><span>code solution for project euler's problem #13 in python.</span></div></li><li><div><span>&quot;&quot;&quot;</span></div></li><li><div><span>from</span> <span>__future__</span> <span>import</span> print_function</div></li><li><div>&nbsp;</div></li><li><div><span>def</span> print_10<span>&#40;</span>number<span>&#41;</span>:</div></li><li><div>    <span>print</span><span>&#40;</span><span>str</span><span>&#40;</span>number<span>&#41;</span><span>&#91;</span><span>0</span>:<span>10</span><span>&#93;</span><span>&#41;</span></div></li><li><div>&nbsp;</div></li><li><div><span>if</span> __name__ <span>==</span> <span>&quot;__main__&quot;</span>:</div></li><li><div>&nbsp;</div></li><li><div>    big_number <span>=</span> <span>&#91;</span> <span>37107287533902102798797998220837590246510135740250</span><span>,</span></div></li><li><div>                   <span>46376937677490009712648124896970078050417018260538</span><span>,</span></div></li><li><div>                   <span>74324986199524741059474233309513058123726617309629</span><span>,</span></div></li><li><div>                   <span>91942213363574161572522430563301811072406154908250</span><span>,</span></div></li><li><div>                   <span>23067588207539346171171980310421047513778063246676</span><span>,</span></div></li><li><div>                   <span>89261670696623633820136378418383684178734361726757</span><span>,</span></div></li><li><div>                   <span>28112879812849979408065481931592621691275889832738</span><span>,</span></div></li><li><div>                   <span>44274228917432520321923589422876796487670272189318</span><span>,</span></div></li><li><div>                   <span>47451445736001306439091167216856844588711603153276</span><span>,</span></div></li><li><div>                   <span>70386486105843025439939619828917593665686757934951</span><span>,</span></div></li><li><div>                   <span>62176457141856560629502157223196586755079324193331</span><span>,</span></div></li><li><div>                   <span>64906352462741904929101432445813822663347944758178</span><span>,</span></div></li><li><div>                   <span>92575867718337217661963751590579239728245598838407</span><span>,</span></div></li><li><div>                   <span>58203565325359399008402633568948830189458628227828</span><span>,</span></div></li><li><div>                   <span>80181199384826282014278194139940567587151170094390</span><span>,</span></div></li><li><div>                   <span>35398664372827112653829987240784473053190104293586</span><span>,</span></div></li><li><div>                   <span>86515506006295864861532075273371959191420517255829</span><span>,</span></div></li><li><div>                   <span>71693888707715466499115593487603532921714970056938</span><span>,</span></div></li><li><div>                   <span>54370070576826684624621495650076471787294438377604</span><span>,</span></div></li><li><div>                   <span>53282654108756828443191190634694037855217779295145</span><span>,</span></div></li><li><div>                   <span>36123272525000296071075082563815656710885258350721</span><span>,</span></div></li><li><div>                   <span>45876576172410976447339110607218265236877223636045</span><span>,</span></div></li><li><div>                   <span>17423706905851860660448207621209813287860733969412</span><span>,</span></div></li><li><div>                   <span>81142660418086830619328460811191061556940512689692</span><span>,</span></div></li><li><div>                   <span>51934325451728388641918047049293215058642563049483</span><span>,</span></div></li><li><div>                   <span>62467221648435076201727918039944693004732956340691</span><span>,</span></div></li><li><div>                   <span>15732444386908125794514089057706229429197107928209</span><span>,</span></div></li><li><div>                   <span>55037687525678773091862540744969844508330393682126</span><span>,</span></div></li><li><div>                   <span>18336384825330154686196124348767681297534375946515</span><span>,</span></div></li><li><div>                   <span>80386287592878490201521685554828717201219257766954</span><span>,</span></div></li><li><div>                   <span>78182833757993103614740356856449095527097864797581</span><span>,</span></div></li><li><div>                   <span>16726320100436897842553539920931837441497806860984</span><span>,</span></div></li><li><div>                   <span>48403098129077791799088218795327364475675590848030</span><span>,</span></div></li><li><div>                   <span>87086987551392711854517078544161852424320693150332</span><span>,</span></div></li><li><div>                   <span>59959406895756536782107074926966537676326235447210</span><span>,</span></div></li><li><div>                   <span>69793950679652694742597709739166693763042633987085</span><span>,</span></div></li><li><div>                   <span>41052684708299085211399427365734116182760315001271</span><span>,</span></div></li><li><div>                   <span>65378607361501080857009149939512557028198746004375</span><span>,</span></div></li><li><div>                   <span>35829035317434717326932123578154982629742552737307</span><span>,</span></div></li><li><div>                   <span>94953759765105305946966067683156574377167401875275</span><span>,</span></div></li><li><div>                   <span>88902802571733229619176668713819931811048770190271</span><span>,</span></div></li><li><div>                   <span>25267680276078003013678680992525463401061632866526</span><span>,</span></div></li><li><div>                   <span>36270218540497705585629946580636237993140746255962</span><span>,</span></div></li><li><div>                   <span>24074486908231174977792365466257246923322810917141</span><span>,</span></div></li><li><div>                   <span>91430288197103288597806669760892938638285025333403</span><span>,</span></div></li><li><div>                   <span>34413065578016127815921815005561868836468420090470</span><span>,</span></div></li><li><div>                   <span>23053081172816430487623791969842487255036638784583</span><span>,</span></div></li><li><div>                   <span>11487696932154902810424020138335124462181441773470</span><span>,</span></div></li><li><div>                   <span>63783299490636259666498587618221225225512486764533</span><span>,</span></div></li><li><div>                   <span>67720186971698544312419572409913959008952310058822</span><span>,</span></div></li><li><div>                   <span>95548255300263520781532296796249481641953868218774</span><span>,</span></div></li><li><div>                   <span>76085327132285723110424803456124867697064507995236</span><span>,</span></div></li><li><div>                   <span>37774242535411291684276865538926205024910326572967</span><span>,</span></div></li><li><div>                   <span>23701913275725675285653248258265463092207058596522</span><span>,</span></div></li><li><div>                   <span>29798860272258331913126375147341994889534765745501</span><span>,</span></div></li><li><div>                   <span>18495701454879288984856827726077713721403798879715</span><span>,</span></div></li><li><div>                   <span>38298203783031473527721580348144513491373226651381</span><span>,</span></div></li><li><div>                   <span>34829543829199918180278916522431027392251122869539</span><span>,</span></div></li><li><div>                   <span>40957953066405232632538044100059654939159879593635</span><span>,</span></div></li><li><div>                   <span>29746152185502371307642255121183693803580388584903</span><span>,</span></div></li><li><div>                   <span>41698116222072977186158236678424689157993532961922</span><span>,</span></div></li><li><div>                   <span>62467957194401269043877107275048102390895523597457</span><span>,</span></div></li><li><div>                   <span>23189706772547915061505504953922979530901129967519</span><span>,</span></div></li><li><div>                   <span>86188088225875314529584099251203829009407770775672</span><span>,</span></div></li><li><div>                   <span>11306739708304724483816533873502340845647058077308</span><span>,</span></div></li><li><div>                   <span>82959174767140363198008187129011875491310547126581</span><span>,</span></div></li><li><div>                   <span>97623331044818386269515456334926366572897563400500</span><span>,</span></div></li><li><div>                   <span>42846280183517070527831839425882145521227251250327</span><span>,</span></div></li><li><div>                   <span>55121603546981200581762165212827652751691296897789</span><span>,</span></div></li><li><div>                   <span>32238195734329339946437501907836945765883352399886</span><span>,</span></div></li><li><div>                   <span>75506164965184775180738168837861091527357929701337</span><span>,</span></div></li><li><div>                   <span>62177842752192623401942399639168044983993173312731</span><span>,</span></div></li><li><div>                   <span>32924185707147349566916674687634660915035914677504</span><span>,</span></div></li><li><div>                   <span>99518671430235219628894890102423325116913619626622</span><span>,</span></div></li><li><div>                   <span>73267460800591547471830798392868535206946944540724</span><span>,</span></div></li><li><div>                   <span>76841822524674417161514036427982273348055556214818</span><span>,</span></div></li><li><div>                   <span>97142617910342598647204516893989422179826088076852</span><span>,</span></div></li><li><div>                   <span>87783646182799346313767754307809363333018982642090</span><span>,</span></div></li><li><div>                   <span>10848802521674670883215120185883543223812876952786</span><span>,</span></div></li><li><div>                   <span>71329612474782464538636993009049310363619763878039</span><span>,</span></div></li><li><div>                   <span>62184073572399794223406235393808339651327408011116</span><span>,</span></div></li><li><div>                   <span>66627891981488087797941876876144230030984490851411</span><span>,</span></div></li><li><div>                   <span>60661826293682836764744779239180335110989069790714</span><span>,</span></div></li><li><div>                   <span>85786944089552990653640447425576083659976645795096</span><span>,</span></div></li><li><div>                   <span>66024396409905389607120198219976047599490197230297</span><span>,</span></div></li><li><div>                   <span>64913982680032973156037120041377903785566085089252</span><span>,</span></div></li><li><div>                   <span>16730939319872750275468906903707539413042652315011</span><span>,</span></div></li><li><div>                   <span>94809377245048795150954100921645863754710598436791</span><span>,</span></div></li><li><div>                   <span>78639167021187492431995700641917969777599028300699</span><span>,</span></div></li><li><div>                   <span>15368713711936614952811305876380278410754449733078</span><span>,</span></div></li><li><div>                   <span>40789923115535562561142322423255033685442488917353</span><span>,</span></div></li><li><div>                   <span>44889911501440648020369068063960672322193204149535</span><span>,</span></div></li><li><div>                   <span>41503128880339536053299340368006977710650566631954</span><span>,</span></div></li><li><div>                   <span>81234880673210146739058568557934581403627822703280</span><span>,</span></div></li><li><div>                   <span>82616570773948327592232845941706525094512325230608</span><span>,</span></div></li><li><div>                   <span>22918802058777319719839450180888072429661980811197</span><span>,</span></div></li><li><div>                   <span>77158542502016545090413245809786882778948721859617</span><span>,</span></div></li><li><div>                   <span>72107838435069186155435662884062257473692284509516</span><span>,</span></div></li><li><div>                   <span>20849603980134001723930671666823555245252804609722</span><span>,</span></div></li><li><div>                   <span>53503534226472524250874054075591789781264330331690</span><span>&#93;</span></div></li><li><div>&nbsp;</div></li><li><div>    print_10<span>&#40;</span><span>sum</span><span>&#40;</span>big_number<span>&#41;</span><span>&#41;</span></div></li></ol></pre></div></p>
<p>and to continue adding in the spice, I have included a solution in Scala:<br />
<div class="geshifilter"><pre class="scala geshifilter-scala"><ol><li><div><a href="http://scala-lang.org"><span>import</span></a> BigInt.<span>_</span></div></li><li><div>&nbsp;</div></li><li><div><a href="http://scala-lang.org"><span>object</span></a> problem<span>_</span>13 <span>&#123;</span></div></li><li><div>    <a href="http://scala-lang.org"><span>def</span></a> main <span>&#40;</span>args <span>:</span> Array<span>&#91;</span>String<span>&#93;</span><span>&#41;</span><span>&#123;</span></div></li><li><div>        <a href="http://scala-lang.org"><span>val</span></a> big<span>_</span>number <span>=</span> List<span>&#40;</span><span>&quot;37107287533902102798797998220837590246510135740250&quot;</span>,</div></li><li><div>                              <span>&quot;46376937677490009712648124896970078050417018260538&quot;</span>,</div></li><li><div>                              <span>&quot;74324986199524741059474233309513058123726617309629&quot;</span>,</div></li><li><div>                              <span>&quot;91942213363574161572522430563301811072406154908250&quot;</span>,</div></li><li><div>                              <span>&quot;23067588207539346171171980310421047513778063246676&quot;</span>,</div></li><li><div>                              <span>&quot;89261670696623633820136378418383684178734361726757&quot;</span>,</div></li><li><div>                              <span>&quot;28112879812849979408065481931592621691275889832738&quot;</span>,</div></li><li><div>                              <span>&quot;44274228917432520321923589422876796487670272189318&quot;</span>,</div></li><li><div>                              <span>&quot;47451445736001306439091167216856844588711603153276&quot;</span>,</div></li><li><div>                              <span>&quot;70386486105843025439939619828917593665686757934951&quot;</span>,</div></li><li><div>                              <span>&quot;62176457141856560629502157223196586755079324193331&quot;</span>,</div></li><li><div>                              <span>&quot;64906352462741904929101432445813822663347944758178&quot;</span>,</div></li><li><div>                              <span>&quot;92575867718337217661963751590579239728245598838407&quot;</span>,</div></li><li><div>                              <span>&quot;58203565325359399008402633568948830189458628227828&quot;</span>,</div></li><li><div>                              <span>&quot;80181199384826282014278194139940567587151170094390&quot;</span>,</div></li><li><div>                              <span>&quot;35398664372827112653829987240784473053190104293586&quot;</span>,</div></li><li><div>                              <span>&quot;86515506006295864861532075273371959191420517255829&quot;</span>,</div></li><li><div>                              <span>&quot;71693888707715466499115593487603532921714970056938&quot;</span>,</div></li><li><div>                              <span>&quot;54370070576826684624621495650076471787294438377604&quot;</span>,</div></li><li><div>                              <span>&quot;53282654108756828443191190634694037855217779295145&quot;</span>,</div></li><li><div>                              <span>&quot;36123272525000296071075082563815656710885258350721&quot;</span>,</div></li><li><div>                              <span>&quot;45876576172410976447339110607218265236877223636045&quot;</span>,</div></li><li><div>                              <span>&quot;17423706905851860660448207621209813287860733969412&quot;</span>,</div></li><li><div>                              <span>&quot;81142660418086830619328460811191061556940512689692&quot;</span>,</div></li><li><div>                              <span>&quot;51934325451728388641918047049293215058642563049483&quot;</span>,</div></li><li><div>                              <span>&quot;62467221648435076201727918039944693004732956340691&quot;</span>,</div></li><li><div>                              <span>&quot;15732444386908125794514089057706229429197107928209&quot;</span>,</div></li><li><div>                              <span>&quot;55037687525678773091862540744969844508330393682126&quot;</span>,</div></li><li><div>                              <span>&quot;18336384825330154686196124348767681297534375946515&quot;</span>,</div></li><li><div>                              <span>&quot;80386287592878490201521685554828717201219257766954&quot;</span>,</div></li><li><div>                              <span>&quot;78182833757993103614740356856449095527097864797581&quot;</span>,</div></li><li><div>                              <span>&quot;16726320100436897842553539920931837441497806860984&quot;</span>,</div></li><li><div>                              <span>&quot;48403098129077791799088218795327364475675590848030&quot;</span>,</div></li><li><div>                              <span>&quot;87086987551392711854517078544161852424320693150332&quot;</span>,</div></li><li><div>                              <span>&quot;59959406895756536782107074926966537676326235447210&quot;</span>,</div></li><li><div>                              <span>&quot;69793950679652694742597709739166693763042633987085&quot;</span>,</div></li><li><div>                              <span>&quot;41052684708299085211399427365734116182760315001271&quot;</span>,</div></li><li><div>                              <span>&quot;65378607361501080857009149939512557028198746004375&quot;</span>,</div></li><li><div>                              <span>&quot;35829035317434717326932123578154982629742552737307&quot;</span>,</div></li><li><div>                              <span>&quot;94953759765105305946966067683156574377167401875275&quot;</span>,</div></li><li><div>                              <span>&quot;88902802571733229619176668713819931811048770190271&quot;</span>,</div></li><li><div>                              <span>&quot;25267680276078003013678680992525463401061632866526&quot;</span>,</div></li><li><div>                              <span>&quot;36270218540497705585629946580636237993140746255962&quot;</span>,</div></li><li><div>                              <span>&quot;24074486908231174977792365466257246923322810917141&quot;</span>,</div></li><li><div>                              <span>&quot;91430288197103288597806669760892938638285025333403&quot;</span>,</div></li><li><div>                              <span>&quot;34413065578016127815921815005561868836468420090470&quot;</span>,</div></li><li><div>                              <span>&quot;23053081172816430487623791969842487255036638784583&quot;</span>,</div></li><li><div>                              <span>&quot;11487696932154902810424020138335124462181441773470&quot;</span>,</div></li><li><div>                              <span>&quot;63783299490636259666498587618221225225512486764533&quot;</span>,</div></li><li><div>                              <span>&quot;67720186971698544312419572409913959008952310058822&quot;</span>,</div></li><li><div>                              <span>&quot;95548255300263520781532296796249481641953868218774&quot;</span>,</div></li><li><div>                              <span>&quot;76085327132285723110424803456124867697064507995236&quot;</span>,</div></li><li><div>                              <span>&quot;37774242535411291684276865538926205024910326572967&quot;</span>,</div></li><li><div>                              <span>&quot;23701913275725675285653248258265463092207058596522&quot;</span>,</div></li><li><div>                              <span>&quot;29798860272258331913126375147341994889534765745501&quot;</span>,</div></li><li><div>                              <span>&quot;18495701454879288984856827726077713721403798879715&quot;</span>,</div></li><li><div>                              <span>&quot;38298203783031473527721580348144513491373226651381&quot;</span>,</div></li><li><div>                              <span>&quot;34829543829199918180278916522431027392251122869539&quot;</span>,</div></li><li><div>                              <span>&quot;40957953066405232632538044100059654939159879593635&quot;</span>,</div></li><li><div>                              <span>&quot;29746152185502371307642255121183693803580388584903&quot;</span>,</div></li><li><div>                              <span>&quot;41698116222072977186158236678424689157993532961922&quot;</span>,</div></li><li><div>                              <span>&quot;62467957194401269043877107275048102390895523597457&quot;</span>,</div></li><li><div>                              <span>&quot;23189706772547915061505504953922979530901129967519&quot;</span>,</div></li><li><div>                              <span>&quot;86188088225875314529584099251203829009407770775672&quot;</span>,</div></li><li><div>                              <span>&quot;11306739708304724483816533873502340845647058077308&quot;</span>,</div></li><li><div>                              <span>&quot;82959174767140363198008187129011875491310547126581&quot;</span>,</div></li><li><div>                              <span>&quot;97623331044818386269515456334926366572897563400500&quot;</span>,</div></li><li><div>                              <span>&quot;42846280183517070527831839425882145521227251250327&quot;</span>,</div></li><li><div>                              <span>&quot;55121603546981200581762165212827652751691296897789&quot;</span>,</div></li><li><div>                              <span>&quot;32238195734329339946437501907836945765883352399886&quot;</span>,</div></li><li><div>                              <span>&quot;75506164965184775180738168837861091527357929701337&quot;</span>,</div></li><li><div>                              <span>&quot;62177842752192623401942399639168044983993173312731&quot;</span>,</div></li><li><div>                              <span>&quot;32924185707147349566916674687634660915035914677504&quot;</span>,</div></li><li><div>                              <span>&quot;99518671430235219628894890102423325116913619626622&quot;</span>,</div></li><li><div>                              <span>&quot;73267460800591547471830798392868535206946944540724&quot;</span>,</div></li><li><div>                              <span>&quot;76841822524674417161514036427982273348055556214818&quot;</span>,</div></li><li><div>                              <span>&quot;97142617910342598647204516893989422179826088076852&quot;</span>,</div></li><li><div>                              <span>&quot;87783646182799346313767754307809363333018982642090&quot;</span>,</div></li><li><div>                              <span>&quot;10848802521674670883215120185883543223812876952786&quot;</span>,</div></li><li><div>                              <span>&quot;71329612474782464538636993009049310363619763878039&quot;</span>,</div></li><li><div>                              <span>&quot;62184073572399794223406235393808339651327408011116&quot;</span>,</div></li><li><div>                              <span>&quot;66627891981488087797941876876144230030984490851411&quot;</span>,</div></li><li><div>                              <span>&quot;60661826293682836764744779239180335110989069790714&quot;</span>,</div></li><li><div>                              <span>&quot;85786944089552990653640447425576083659976645795096&quot;</span>,</div></li><li><div>                              <span>&quot;66024396409905389607120198219976047599490197230297&quot;</span>,</div></li><li><div>                              <span>&quot;64913982680032973156037120041377903785566085089252&quot;</span>,</div></li><li><div>                              <span>&quot;16730939319872750275468906903707539413042652315011&quot;</span>,</div></li><li><div>                              <span>&quot;94809377245048795150954100921645863754710598436791&quot;</span>,</div></li><li><div>                              <span>&quot;78639167021187492431995700641917969777599028300699&quot;</span>,</div></li><li><div>                              <span>&quot;15368713711936614952811305876380278410754449733078&quot;</span>,</div></li><li><div>                              <span>&quot;40789923115535562561142322423255033685442488917353&quot;</span>,</div></li><li><div>                              <span>&quot;44889911501440648020369068063960672322193204149535&quot;</span>,</div></li><li><div>                              <span>&quot;41503128880339536053299340368006977710650566631954&quot;</span>,</div></li><li><div>                              <span>&quot;81234880673210146739058568557934581403627822703280&quot;</span>,</div></li><li><div>                              <span>&quot;82616570773948327592232845941706525094512325230608&quot;</span>,</div></li><li><div>                              <span>&quot;22918802058777319719839450180888072429661980811197&quot;</span>,</div></li><li><div>                              <span>&quot;77158542502016545090413245809786882778948721859617&quot;</span>,</div></li><li><div>                              <span>&quot;72107838435069186155435662884062257473692284509516&quot;</span>,</div></li><li><div>                              <span>&quot;20849603980134001723930671666823555245252804609722&quot;</span>,</div></li><li><div>                              <span>&quot;53503534226472524250874054075591789781264330331690&quot;</span><span>&#41;</span> map <span>&#123;</span>BigInt<span>&#40;</span><span>_</span><span>&#41;</span><span>&#125;</span></div></li><li><div>        <a href="http://scala-lang.org"><span>val</span></a> sums <span>=</span> big<span>_</span>number sum</div></li><li><div>        <a href="http://scala-lang.org"><span>val</span></a> su <span>=</span> sums toString</div></li><li><div>        <a href="http://scala-lang.org"><span>val</span></a> su10 <span>=</span> su take <span>10</span></div></li><li><div>        println<span>&#40;</span>su10<span>&#41;</span></div></li><li><div>    <span>&#125;</span></div></li><li><div><span>&#125;</span></div></li></ol></pre></div><br />
Some of you may be wondering, “Why a Scala solution?”  To which I respond, “Why not?”  Because that's a little short, I'll add that it has something to do with Scala starting to gain traction in the industry and me seeing if I would like to get paid to program in it.</p>
<p>The solution, in all three languages, is pretty simple. The recipe essentially says, “Put all numbers into a list.  Get the sum of that list, turn that number into a string, and get the first 10 characters of that string.”</p>
<p>Times:<br />
Haskell (compiled)   : real	0m0.004s<br />
Haskell (runghc)     : real	0m0.314s<br />
Python               : real	0m0.059s<br />
Scala   (compiled)   : real	0m0.757s</p>
<p>For the most part it's pretty standard in these tests to see performance times such that Haskell (compiled)  Python  Haskell (runghc). Java and Perl usually fall somewhere between the Haskell (compiled) and Python, in that order. To see Scala be 2x slower than Haskell (runghc) was a shocker.  The only thing that makes sense to me for the slowdown is having to use the BigInt library. That is probably the biggest thing I took away from these time tests - if I want to do REALLY large number crunching and performance DOES matter, JVM-based languages might not be the best option. </p>
<p>A few thoughts on Scala:<br />
If I haven't stated it already in this blog, I should now give the disclaimer that I'm not a Java fan.  I know it still has its loyal followers, but I'm not one of them.  Moving on.  This was my first time working with Scala, and I'd like to finally welcome Java to the 21st century.  While doing some research on the Scala language itself I read that “the industry” was moving to replace Java with Scala.  I welcome that change.  Does that mean I “like” Scala?  The honest answer is, to butcher the quote the appliances from the Flintstones, “Eh, it's a language.” Scala is definitely an improvement over Java – not really that hard to do in my opinion – but, the language still feels unpolished.  One quick way to kill the interpreter in Scala is to type “Int” then hit the enter key.  Instead of error-ing out, the interpreter does a great job of interpreting a crash test car hitting a cement wall (I had to restart the whole thing.)  When I tried the same “technique” in the Python interpreter, I got  as a response and for Haskell's interpreter I received “Not in scope: data constructor `Int'”.  I also found Scala's function composition to be a little lacking when compared to Haskell.  I wasn't able to cleanly change the BigInt data type to String, and then only print out ten characters without requiring three separate val's.  Yes, I could have used one var instead, but that's beside the point. I will admit it could be my inexperience with the language showing, so if anyone knows a smoother way to do this in Scala please share it in the comments.</p>
<p>All that being said, I do like the way Scala is trying to handle the reducing of Java's dot notation, and I think it's starting to make strides in the right direction in other areas.  I'm open to working with Scala more, and look forward to seeing how it evolves over the next few years.  </p>]]></description>
    <link><![CDATA[http://scrollingtext.org/project-euler-problem-13]]></link>
    <pubDate>2012-05-22 16:48:04</pubDate>
  </item>
  <item>
    <title><![CDATA[Daniel Greenfeld: Simple Django email form using CBV]]></title>
    <description><![CDATA[<p>Here's a simple <tt class="docutils literal">FormView</tt> Class Based Views for <a class="reference external" href="http://djangoproject.com">Django</a>. Here is a sample of how to do one as a simple email form. There is no CAPTCHA in this example, that's the topic of a future blog post.</p>
<p>This version requires the following packages <tt class="docutils literal">pip</tt> installed into your <tt class="docutils literal">virtualenv</tt>.</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">django-crispy-forms</span></tt> so we can do Python driven layouts.</li>
<li><tt class="docutils literal"><span class="pre">django-floppyforms</span></tt> so we get HTML5 elements for free.</li>
</ul>
<p>They also need to be added to your list of INSTALLED_APPS:</p>
<div class="highlight"><pre><span class="n">INSTALLED_APPS</span> <span class="o">+=</span> <span class="p">(</span>
    <span class="s">'crispy_forms'</span><span class="p">,</span>
    <span class="s">'floppyforms'</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>In myapp.forms.py:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">crispy_forms.helper</span> <span class="kn">import</span> <span class="n">FormHelper</span>
<span class="kn">from</span> <span class="nn">crispy_forms.layout</span> <span class="kn">import</span> <span class="n">Submit</span>
<span class="kn">import</span> <span class="nn">floppyforms</span> <span class="kn">as</span> <span class="nn">forms</span>

<span class="k">class</span> <span class="nc">ContactForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>

    <span class="n">name</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">email</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">EmailField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">subject</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
    <span class="n">message</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">Textarea</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">helper</span> <span class="o">=</span> <span class="n">FormHelper</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">helper</span><span class="o">.</span><span class="n">add_input</span><span class="p">(</span><span class="n">Submit</span><span class="p">(</span><span class="s">'submit'</span><span class="p">,</span> <span class="s">'Submit'</span><span class="p">))</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">ContactForm</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
<p>In myapp.views.py:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.core.mail</span> <span class="kn">import</span> <span class="n">send_mail</span>
<span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">FormView</span>

<span class="kn">from</span> <span class="nn">myapp.forms</span> <span class="kn">import</span> <span class="n">ContactForm</span>

<span class="k">class</span> <span class="nc">ContactFormView</span><span class="p">(</span><span class="n">FormView</span><span class="p">):</span>

    <span class="n">form_class</span> <span class="o">=</span> <span class="n">ContactForm</span>
    <span class="n">template_name</span> <span class="o">=</span> <span class="s">&quot;myapp/email_form.html&quot;</span>
    <span class="n">success_url</span> <span class="o">=</span> <span class="s">'/email-sent/'</span>

    <span class="k">def</span> <span class="nf">form_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">form</span><span class="p">):</span>
        <span class="n">message</span> <span class="o">=</span> <span class="s">&quot;{name} / {email} said: &quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
            <span class="n">name</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'name'</span><span class="p">),</span>
            <span class="n">email</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'email'</span><span class="p">))</span>
        <span class="n">message</span> <span class="o">+=</span> <span class="s">&quot;</span><span class="se">\n\n</span><span class="s">{0}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'message'</span><span class="p">))</span>
        <span class="n">send_mail</span><span class="p">(</span>
            <span class="n">subject</span><span class="o">=</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'subject'</span><span class="p">),</span>
            <span class="n">message</span><span class="o">=</span><span class="n">message</span><span class="p">,</span>
            <span class="n">from_email</span><span class="o">=</span><span class="s">'contact-form@myapp.com'</span><span class="p">,</span>
            <span class="n">recipient_list</span><span class="o">=</span><span class="p">[</span><span class="n">settings</span><span class="o">.</span><span class="n">LIST_OF_EMAIL_RECIPIENTS</span><span class="p">],</span>
        <span class="p">)</span>
        <span class="k">return</span> <span class="nb">super</span><span class="p">(</span><span class="n">ContactFormView</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">form_valid</span><span class="p">(</span><span class="n">form</span><span class="p">)</span>
</pre></div>
<p>In templates/myapp/email_form.html:</p>
<div class="highlight"><pre>{% extends 'base.html' %}
{% load crispy_forms_tags %}

{% block title %}Send an email{% endblock %}

{% block content %}
    <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;row&quot;</span><span class="nt">&gt;</span>
        <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;span6&quot;</span><span class="nt">&gt;</span>
            <span class="nt">&lt;h1&gt;</span>Send an email<span class="nt">&lt;/h1&gt;</span>
            {% crispy form form.helper %}
        <span class="nt">&lt;/div&gt;</span>
    <span class="nt">&lt;/div&gt;</span>
{% endblock %}

{% block extrajs %}
<span class="nt">&lt;script </span><span class="na">src=</span><span class="s">&quot;{{ STATIC_URL }}js/jquery-1.7.1.min.js&quot;</span><span class="nt">&gt;&lt;/script&gt;</span>
<span class="nt">&lt;script </span><span class="na">type=</span><span class="s">&quot;text/javascript&quot;</span><span class="nt">&gt;</span>
<span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">$</span><span class="p">(</span><span class="s1">'#id_name'</span><span class="p">).</span><span class="nx">focus</span><span class="p">()</span>
<span class="p">});</span>
<span class="nt">&lt;/script&gt;</span>
{% endblock %}
</pre></div>
<div class="section" id="tomorrow-s-blog-post">
<h2>Tomorrow's blog post</h2>
<p>In tomorrow's post I'll show how to add CAPTCHA into your project to help reduce spam messages.</p>
</div>
<div class="section" id="want-to-learn-more">
<h2>Want to learn more?</h2>
<p>If you live in the Los Angeles area and want to learn more about Django, everything from the basics to setting up a Content Management System or E-Commerce system, check out our Django (and <a class="reference external" href="http://python.org">Python</a>) training at <a class="reference external" href="https://academy.cartwheelweb.com">Cartwheel Academy</a>.</p>
</div>]]></description>
    <link><![CDATA[http://pydanny.com/simple-django-email-form-using-cbv.html]]></link>
    <pubDate>2012-05-22 09:30:00</pubDate>
  </item>
  <item>
    <title><![CDATA[Python 4 Kids: Minecraft Config Editor: Tkinter Text Widget and Frames]]></title>
    <description><![CDATA[<p><a href="http://www.ibras.dk/montypython/episode06.htm#6"><em>Furtively he looks round, then takes from the desk drawer a comic-book entitled &#8216;Thrills and Adventure&#8217;. We see the frames of the comic strip. A Superman-type character and a girl are shrinking from an explosion. She is saying &#8216;My God, his nose just exploded with enough force to destroy his kleenex&#8217;. In the next frame, the Superman character is saying &#8216;If only I had a kleenex to lend him &#8211; or even a linen handkerchief &#8211; but these trousers&#8230;!! No back pocket!&#8217; In the frame beneath, he flies from side to side attempting to escape; finally he breaks through, bringing the two frames above down on himself. Cut to a picture of a safety curtain. </em></a></p>
<p>Last tutorial we covered &#8216;parsing&#8217;.  We broke a standard config file up into separate lines and then we broke each line into pairs, each pair having a &#8216;key&#8217; and a &#8216;value&#8217;.   If we&#8217;re to edit the file, we need a way to edit the values (and after that we&#8217;ll write the edited values back to the config file).  We&#8217;re going to see how to use <em>Tkinter</em> to do that in this tutorial.</p>
<p>Let&#8217;s start thinking about how a single key/value pair will look.  I am thinking of having the key on the left hand side with a space to input the value on the right hand side.  To do this we will use the <a href="http://python4kids.wordpress.com/2011/07/18/tkinter-tinkering-graphical-user-interfaces/">Label widget that we&#8217;ve met before</a> and the <em>Text widget</em>.  <em>Label</em> is used to display static text &#8211; ie text that will not be edited, while the <em>Text</em> <em>widget</em> allows the user to edit the text which is displayed in the <em>widget,</em> and for the program to read what is entered in the <em>widget. </em> The <em>Text widget</em> is the GUI equivalent of <em>raw_inpu</em>t() that we met so long ago.</p>
<p><pre class="brush: python;">
from Tkinter import *

root = Tk()
labelWidget = Label(root,text=&quot;A key:&quot;)
textWidget = Text(root)

textWidget.insert('1.0',&quot;A Value&quot;)
labelWidget.pack(side=LEFT)
textWidget.pack(side=RIGHT)

root.mainloop()

</pre></p>
<p>Here we first create a <em>Tk()</em> <em>object,</em> then create a <em>label widget</em> and a <em>text widget</em> in that object.   We pack the label first and we pack it on the LEFT side (LEFT is actually the name of a constant in Tk which Tk translates to &#8216;put this on the left&#8217;) and pack the <em>text widget</em> on the right side.  At location &#8220;1.0&#8243; we add the text &#8220;A Value&#8221; to the <em>Text widget</em>.  Here the number &#8220;1.0&#8243; means &#8220;row 1, at character position 0&#8243;, which is to say, at the very start of the text.</p>
<p>If I run this code I get something like this:</p>
<p><a href="http://python4kids.files.wordpress.com/2012/03/p4ktkinter120306.jpeg"><img class="aligncenter size-full wp-image-420" title="p4kTkinter120306" src="http://python4kids.files.wordpress.com/2012/03/p4ktkinter120306.jpeg?w=630" alt="" /></a></p>
<p>Which is sort of what I wanted &#8211; a label on the left, and an editable text box on the right (can you see the cursor in the screen shot?) &#8211; click the <em>close window widget</em> in the top right corner to close the window.</p>
<p>Exercise:  Type something into the text box.  See if you can do it to the label.</p>
<p>However, this isn&#8217;t really what I wanted.  I wanted a little text box, not the enormous one I&#8217;ve got here.  Since I didn&#8217;t specify a height and width for it, the <em>Text widget</em> used its default size (which is way too big).  The user also doesn&#8217;t have any way to tell the program to use (or cancel) the edit.  Let&#8217;s change the code to add an ok and cancel button, and to change the size of the<em> text widget</em>.</p>
<p>Here is a revised version which is nearer to what I was looking for:</p>
<p><pre class="brush: python;">
from Tkinter import *

def okClicked():
    '''Get the edited values and write them to the file then quit'''
    #TODO: get values and write them to the file!
    exit()
def cancelClicked():
    '''Cancel edits and quit'''
    exit()

root = Tk()
labelWidget = Label(root,text=&quot;A key:&quot;)
textWidget = Text(root, width=60, height = 1)
okWidget = Button(root, text= &quot;Ok&quot;, command = okClicked)
cancelWidget = Button(root, text=&quot;Cancel&quot;, command = cancelClicked)

textWidget.insert('1.0',&quot;A Value&quot;)
labelWidget.pack(side=LEFT)
cancelWidget.pack(side=RIGHT)
okWidget.pack(side=RIGHT)

textWidget.pack(side=RIGHT)

root.mainloop()
</pre></p>
<p>This gives:</p>
<p><a href="http://python4kids.files.wordpress.com/2012/03/p4ktkinter120306b.jpeg"><img class="aligncenter size-full wp-image-421" title="p4kTkinter120306B" src="http://python4kids.files.wordpress.com/2012/03/p4ktkinter120306b.jpeg?w=630" alt="" /></a></p>
<p>I have added a couple of functions to be run when the ok and cancel buttons are clicked.  The ok button&#8217;s function is still a little empty at the moment though&#8230;  I have specified the <em>width</em> to be 60 <em>characters</em> and the <em>height</em> to be one row.  Note these are <strong>not</strong> pixel measurements.  If you change the size of the font the text box will also change.</p>
<p>Notice also the way the geometry is working.  The widgets which are pack(side=RIGHT) are added at the right in the order they are packed.  If the buttons were packed last they would be between the label and the text window.</p>
<p><strong>Exercise:</strong> change the program so that the widgets are packed in a different order. What happens if you try side=TOP or side=BOTTOM?</p>
<p>The value can be edited by the user typing directly into the text box.  The text in the text box can also be edited programmatically, which is to say its contents can be changed by the program without the user typing.  See the <a href="http://www.pythonware.com/library/tkinter/introduction/text.htm">Tkinter documentation</a> for details &#8211; or clamour on this site and I&#8217;ll add a tute.</p>
<p>One thing that I don&#8217;t like about this layout is the fact the buttons are on the same line as the key label and value text.  When you did the exercise above, you should have noticed that side=TOP and side=BOTTOM don&#8217;t really help, since you can&#8217;t position the ok and cancel buttons on the same line.  What we need to use is the<em> Frame widget</em>.  <em>Frames</em> can be thought of as empty spaces in which you can group widgets together.  By treating the widgets within the Frame as a group, additional layouts can be achieved.   <em>Frames</em> can be packed inside other frames. We will use two frames, one on top of the other.  In the first frame we pack the label and text widgets.  In the second frame we pack the two buttons.</p>
<p>Here is the code:</p>
<p><pre class="brush: python;">
from Tkinter import *

def okClicked():
    '''Get the edited values and write them to the file then quit'''
    #TODO: get values and write them to the file!
    exit()
def cancelClicked():
    '''Cancel edits and quit'''
    exit()

root = Tk()

topFrame = Frame(root)
bottomFrame = Frame(root)
labelWidget = Label(topFrame,text=&quot;A key:&quot;)
textWidget = Text(topFrame, width=60, height = 1)
okWidget = Button(bottomFrame, text= &quot;Ok&quot;, command = okClicked)
cancelWidget = Button(bottomFrame, text=&quot;Cancel&quot;, command = cancelClicked)

textWidget.insert('1.0',&quot;A Value&quot;)
labelWidget.pack(side=LEFT)
cancelWidget.pack(side=RIGHT)
okWidget.pack(side=LEFT)
textWidget.pack(side=RIGHT)

topFrame.pack(side=TOP)
bottomFrame.pack(side=BOTTOM)

root.mainloop()

</pre></p>
<p><a href="http://python4kids.files.wordpress.com/2012/03/p4ktkinter120306c.jpeg"><img class="aligncenter size-full wp-image-422" title="p4kTkinter120306C" src="http://python4kids.files.wordpress.com/2012/03/p4ktkinter120306c.jpeg?w=630" alt="" /></a></p>
<p>This is more like what I wanted (notice you can&#8217;t see the individual frames).  One might <a href="http://www.thefreedictionary.com/quibble">quibble</a> with the location of the ok and cancel buttons.  Maybe they should be offset a little from the centre?  Maybe they should be off to one side.  In any event they are in the general layout that i was looking for: a key label and an editable value text above the ok and cancel buttons. Notice in the code that the widgets we used before have had their parent changed from root to either topFrame or bottomFrame?  However these Frame widgets have root as their parent.   So the original widgets we were using have effectively been pushed down one level in the hierarchy.</p>
<p>We still don&#8217;t know how to get what the user has typed into the text box, but maybe I can leave that as an exercise for the reader (try textWidget.get(&#8220;1.0&#8243;,END)).</p>
<p><strong>Homework:</strong>  change the okClicked() function so that it prints the contents of the text box before exiting.  Use the hint in the previous paragraph.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/python4kids.wordpress.com/418/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/python4kids.wordpress.com/418/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/python4kids.wordpress.com/418/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/python4kids.wordpress.com/418/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/python4kids.wordpress.com/418/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/python4kids.wordpress.com/418/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/python4kids.wordpress.com/418/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/python4kids.wordpress.com/418/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/python4kids.wordpress.com/418/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/python4kids.wordpress.com/418/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/python4kids.wordpress.com/418/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/python4kids.wordpress.com/418/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/python4kids.wordpress.com/418/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/python4kids.wordpress.com/418/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=python4kids.wordpress.com&blog=14472219&post=418&subd=python4kids&ref=&feed=1" width="1" height="1" />]]></description>
    <link><![CDATA[http://python4kids.wordpress.com/2012/03/06/minecraft-config-editor-tkinter-text-widget-and-frame/]]></link>
    <pubDate>2012-05-22 05:40:03</pubDate>
  </item>
  <item>
    <title><![CDATA[Python 4 Kids: Minecraft Config: Subclassing and Inheritance, Editing all config items]]></title>
    <description><![CDATA[<p><em><a href="http://www.ibras.dk/montypython/finalripoff.htm#String">Mr. Simpson:     Good. Well I have this large quantity of string, a hundred and twenty-two thousand miles of it to be exact, which I inherited, and I thought if I advertised it&#8211;<br />
Wapcaplet:     Of course! A national campaign. Useful stuff, string, no trouble there.<br />
Mr. Simpson:     Ah, but there&#8217;s a snag, you see. Due to bad planning, the hundred and twenty-two thousand miles is in three inch lengths. So it&#8217;s not very useful. </a></em></p>
<p>In the previous tutorial we learnt that when we pack <em>Tkinter</em> <em>objects,</em> the order in which we pack them affects how they are displayed in the GUI.  We used a <em>Text</em> <em>widget</em> to enable the user to edit text in the GUI.  We also learnt to use a <em>Frame</em> <em>widget</em> to help with the layout of our GUI.  In particular, we put a <em>Label</em> and a <em>Text</em> widget together into one <em>Frame,</em> and put an ok and cancel <em>Button</em> into another.   For homework you needed to get data from the <em>Text</em> widget.</p>
<p>In order to display all of the configuration options we are going to go a bit nutty using <em>Frames.  </em> We will eventually (but not today) use one <em>Frame</em> to hold all of the configuration options, and another Frame to hold the Ok and Cancel buttons.  But that&#8217;s not all!  We will also use a Frame to house each configuration option (ie key and value pair).  Before we do that though, we need to remember where we were up to reading and parsing the server.properties file.</p>
<p>Here is the code we finished with two tutorials ago, excluding the last couple of lines (which printed out the results) for your reference if you need it (click to expand):</p>
<p><pre class="brush: python; collapse: true; light: false; toolbar: true;">
'''Minecraft config editor:
This is an editor for the Minecraft server.properties file.  It:
* opens the file server.properties
* reads, then closes the file
* parses each line by
-- stripping leading and trailing whitespace
-- if the line starts with &quot;#&quot;, marks it as a comment
-- splits the line into a key, value pair, with the pair separated by a &quot;=&quot; sign
-- if the value of the pair is either &quot;true&quot; or &quot;false&quot;, the entry is marked as a boolean (ie its only values are either true or false)
* displays each key, value entry on the screen allowing you to edit it
* renames the server.properties file to server.properties.bup (overwriting any existing file of that name from earlier edits)
* opens a new file called server.properties
* writes each of the entries to that new file
* closes the server.properties file.
'''

class configItem(object):  # name of the class, it is based on an object called 'object'
  def __init__(self, line):# this is called each time an instance of the class is created
    line = line.strip()  # this removes any white space at the start or end of the line
    # if it starts with a # it's a comment so check for it
    if line[:1] == &quot;#&quot;:
       self.configKey = &quot;#&quot;
       self.configVal = line[1:]
    else:  # otherwise assume it's of the form x = y
       spam = line.split(&quot;=&quot;)
       self.configKey = spam[0]
       self.configVal = spam[1]
    # now check to see whether the config item takes only the values &quot;true&quot; and &quot;false&quot;
    if self.configVal.lower() in [&quot;true&quot;,&quot;false&quot;]:
       self.isTrueFalse = True
    else:
       self.isTrueFalse = False

# get data from the file

fileName = &quot;server.properties&quot;
fileObject = open(fileName,'rb')
fileData = fileObject.read()
fileObject.close()

configLines = []

for line in fileData.split('\n'):  # this splits it into individual lines
    if line.strip()=='':
      continue
    configLines.append(configItem(line))
</pre></p>
<p>If you remember we defined a <em>class</em> called <em>configItem. </em> We read the lines from the config file and used each line to create instances of <em>configItem. </em> We stored those in an <em>array</em> called <em>configLines. </em> Each <em>instance</em> has two <em>attributes</em> &#8211; <em>configKey</em> and <em>configVal</em> (that is, the things on the left and right hand side of the equals respectively).  In the last tutorial for one key, value pair we:</p>
<ul>
<li>created a <em>label</em> and set it equal to <em>configKey;</em></li>
<li>created a <em>text</em> widget and set its value to <em>configVal;</em> and, finally,</li>
<li>created a <em>frame</em> in which to pack each of these.</li>
</ul>
<p>Now we have to do that for each and every entry in the <em>array. </em> There are plenty of ways to do this.  However, I am going to do it by<em> &#8220;subclassing&#8221;</em> the <em>configItem</em> <em>class. </em> That is, I am going to create a new <em>class</em> which is based on (&#8220;inherits from&#8221; or &#8220;is a subclass of&#8221;) the <em>configItem</em> <em>class. </em> It has the features of the <em>configItem class</em> but will also store some stuff relating to the <em>Tkinter</em> widgets that we will need.  This is the new class which I&#8217;ve called <em>guiConfigItem:</em></p>
<p><pre class="brush: python;">
class guiConfigItem(configItem):
  def __init__(self,line):
    super(guiConfigItem,self).__init__(line)  # run configItem's __init__ method
    self.frame = Frame()
    self.keyLabel = Label(self.frame, text = self.configKey)
    self.valueEntry = Entry(self.frame, width=&quot;60&quot;)
    self.valueEntry.insert(&quot;0&quot;,self.configVal)
    self.keyLabel.pack(side=LEFT )
    self.valueEntry.pack(side=RIGHT)
    self.frame.pack(side=TOP)
</pre></p>
<p>Some things to note about this class:</p>
<ul>
<li>instead of the first line ending<em> &#8220;(object):&#8221;</em> like the other classes we&#8217;ve seen, this one ends <em>&#8220;(configItem):&#8221;. </em> This means that <em>guiConfigItem&#8217;s</em> immediate parent is <em>configItem. </em> However, since <em>configItem</em> is based on <em>object,</em> in the end, so is <em>guiConfigItem.</em></li>
<li>it takes the same <em>initialisation</em> parameters as <em>configItem</em> (that is, self and line)</li>
<li>the first thing it does in initialising stuff is to call <em>super(guiConfigItem,self).__init__(line). </em> This runs <em>configItem&#8217;s __init__</em> <em>method,</em> so every <em>guiConfigItem</em> starts with the same initialisation that <em>configItem</em> would have</li>
<li>it starts by creating a <em>Frame,</em> stores it in <em>self.frame,</em> then, inside the frame, it creates a <em>label</em> and an <em>Entry</em> widget.  An <em>Entry</em> widget is the single line version of the <em>Text</em> widget we used last time, and it should be good enough for our purposes.</li>
<li>you can tell that the <em>Label</em> and <em>Entry</em> widgets are created inside the frame which has been created because the first parameter passed to them is self.frame.</li>
<li>the <em>Label widge</em>t is packed to the LEFT, and the <em>Entry widget</em> to the RIGHT.  the frame is also packed, but it is packed to TOP (ie it will make a list from top to bottom)</li>
</ul>
<p>This <em>class</em> is added after the definition of the <em>configItem</em> <em>class. </em> In order to get it working we just have to make a four changes to the program.  We will:</p>
<ul>
<li>import Tkinter &#8211; <em>from Tkinter import *</em>;</li>
<li>create a root window in which to pack things -<em> root =Tk()</em>;</li>
<li>change the loop to create guiConfigItems rather than configItems &#8211; <em>configLines.append(guiConfigItem(line=line))</em>; and</li>
<li>we will start the gui with a mainloop() &#8211; <em>root.mainloop()</em></li>
</ul>
<p>Here is the updated source code:</p>
<p><pre class="brush: python; collapse: true; light: false; toolbar: true;">

'''Minecraft config editor:
This is an editor for the Minecraft server.properties file.  It:
* opens the file server.properties
* reads, then closes the file
* parses each line by
-- stripping leading and trailing whitespace
-- if the line starts with &quot;#&quot;, marks it as a comment
-- splits the line into a key, value pair, with the pair separated by a &quot;=&quot; sign
-- if the value of the pair is either &quot;true&quot; or &quot;false&quot;, the entry is marked as a boolean (ie its only values are either true or false)
* displays each key, value entry on the screen allowing you to edit it
* renames the server.properties file to server.properties.bup (overwriting any existing file of that name from earlier edits)
* opens a new file called server.properties
* writes each of the entries to that new file
* closes the server.properties file.
'''

from Tkinter import *

class configItem(object):  # name of the class, it is based on an object called 'object'
  def __init__(self, line):# this is called each time an instance of the class is created
    line = line.strip()  # this removes any white space at the start or end of the line
    # if it starts with a # it's a comment so check for it
    if line[:1] == &quot;#&quot;:
       self.configKey = &quot;#&quot;
       self.configVal = line[1:]
    else:  # otherwise assume it's of the form x = y
       spam = line.split(&quot;=&quot;)
       self.configKey = spam[0]
       self.configVal = spam[1]
    # now check to see whether the config item takes only the values &quot;true&quot; and &quot;false&quot;
    if self.configVal.lower() in [&quot;true&quot;,&quot;false&quot;]:
       self.isTrueFalse = True
    else:
       self.isTrueFalse = False

class guiConfigItem(configItem):
  def __init__(self,line):
    super(guiConfigItem,self).__init__(line)  # run configItem's __init__ method
    self.frame = Frame()
    self.keyLabel = Label(self.frame, text = self.configKey)
    self.valueEntry = Entry(self.frame, width=&quot;60&quot;)
    self.valueEntry.insert(&quot;0&quot;,self.configVal)
    self.keyLabel.pack(side=LEFT )
    self.valueEntry.pack(side=RIGHT)
    self.frame.pack(side=TOP)

# get data from the file

fileName = &quot;server.properties&quot;
fileObject = open(fileName,'rb')
fileData = fileObject.read()
fileObject.close()

root = Tk()
configLines = []

for line in fileData.split('\n'):  # this splits it into individual lines
    if line.strip()=='':
      continue
    configLines.append(guiConfigItem(line=line))

root.mainloop()
</pre></p>
<p>When I run this I get:</p>
<p><a href="http://python4kids.files.wordpress.com/2012/03/p4ktkinter120313.jpeg"><img class="aligncenter size-full wp-image-430" title="p4kTkinter120313" src="http://python4kids.files.wordpress.com/2012/03/p4ktkinter120313.jpeg?w=630" alt="" /></a><br />
Wow, is that magic? The way we defined the class meant that each of the instances packed itself for us as we created them.  This is an example of why using classes can be so much fun.</p>
<p><strong>Exercise:</strong> how might you do the same thing without using classes?</p>
<p>That said, the alignment is a little wonky.   This is because each of the individual frames (there is one on each line) are different sizes.  The overall window is big enough to fit the biggest, but that means that the smaller lines aren&#8217;t big enough.  This can be remedied by adding fill=&#8221;x&#8221; (that is, fill in the x (horizontal) direction if necessary to the pack command for each of the Frames:</p>
<pre>self.frame.pack(side=TOP, fill="x")</pre>
<p>Now the window looks much better:</p>
<p><a href="http://python4kids.files.wordpress.com/2012/03/p4ktkinter120313b.jpeg"><img class="aligncenter size-full wp-image-431" title="p4kTkinter120313B" src="http://python4kids.files.wordpress.com/2012/03/p4ktkinter120313b.jpeg?w=630" alt="" /></a></p>
<p><strong>Exercise:</strong> confirm that you can edit the values on the right.</p>
<p><strong>Exercise 2:</strong> check through our docstring to see what we&#8217;ve done so far and what we&#8217;ve got left to do.</p>
<p>The complete source code with the final edit is below.</p>
<p><pre class="brush: python; collapse: true; light: false; toolbar: true;">
'''Minecraft config editor:
This is an editor for the Minecraft server.properties file.  It:
* opens the file server.properties
* reads, then closes the file
* parses each line by
-- stripping leading and trailing whitespace
-- if the line starts with &quot;#&quot;, marks it as a comment
-- splits the line into a key, value pair, with the pair separated by a &quot;=&quot; sign
-- if the value of the pair is either &quot;true&quot; or &quot;false&quot;, the entry is marked as a boolean (ie its only values are either true or false)
* displays each key, value entry on the screen allowing you to edit it
* renames the server.properties file to server.properties.bup (overwriting any existing file of that name from earlier edits)
* opens a new file called server.properties
* writes each of the entries to that new file
* closes the server.properties file.
'''

from Tkinter import *

class configItem(object):  # name of the class, it is based on an object called 'object'
  def __init__(self, line):# this is called each time an instance of the class is created
    line = line.strip()  # this removes any white space at the start or end of the line
    # if it starts with a # it's a comment so check for it
    if line[:1] == &quot;#&quot;:
       self.configKey = &quot;#&quot;
       self.configVal = line[1:]
    else:  # otherwise assume it's of the form x = y
       spam = line.split(&quot;=&quot;)
       self.configKey = spam[0]
       self.configVal = spam[1]
    # now check to see whether the config item takes only the values &quot;true&quot; and &quot;false&quot;
    if self.configVal.lower() in [&quot;true&quot;,&quot;false&quot;]:
       self.isTrueFalse = True
    else:
       self.isTrueFalse = False

class guiConfigItem(configItem):
  def __init__(self,line):
    super(guiConfigItem,self).__init__(line)  # run configItem's __init__ method
    self.frame = Frame()
    self.keyLabel = Label(self.frame, text = self.configKey)
    self.valueEntry = Entry(self.frame, width=&quot;60&quot;)
    self.valueEntry.insert(&quot;0&quot;,self.configVal)
    self.keyLabel.pack(side=LEFT )
    self.valueEntry.pack(side=RIGHT)
    self.frame.pack(side=TOP, fill=&quot;x&quot;)

# get data from the file

fileName = &quot;server.properties&quot;
fileObject = open(fileName,'rb')
fileData = fileObject.read()
fileObject.close()

root = Tk()
configLines = []

for line in fileData.split('\n'):  # this splits it into individual lines
    if line.strip()=='':
      continue
    configLines.append(guiConfigItem(line=line))

root.mainloop()
</pre></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/python4kids.wordpress.com/427/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/python4kids.wordpress.com/427/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/python4kids.wordpress.com/427/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/python4kids.wordpress.com/427/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/python4kids.wordpress.com/427/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/python4kids.wordpress.com/427/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/python4kids.wordpress.com/427/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/python4kids.wordpress.com/427/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/python4kids.wordpress.com/427/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/python4kids.wordpress.com/427/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/python4kids.wordpress.com/427/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/python4kids.wordpress.com/427/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/python4kids.wordpress.com/427/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/python4kids.wordpress.com/427/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=python4kids.wordpress.com&blog=14472219&post=427&subd=python4kids&ref=&feed=1" width="1" height="1" />]]></description>
    <link><![CDATA[http://python4kids.wordpress.com/2012/03/13/minecraft-config-subclassing-and-inheritance-editing-all-config-items/]]></link>
    <pubDate>2012-05-22 05:39:58</pubDate>
  </item>
  <item>
    <title><![CDATA[Python 4 Kids: Almost There! Adding Methods to Our Classes]]></title>
    <description><![CDATA[<p><a href="http://www.ibras.dk/montypython/episode31.htm">Mr Mann     Ee ecky thump! (indicates more power)<br />
Third Booth     Ee ecky thump!<br />
Mr Mann     Excellent.<br />
Third Booth     Thank you, sir. (puts earphones on, listens)<br />
Mr Mann     It&#8217;s a really quick method of learning.</a></p>
<p>There are two more things to do with our Minecraft config file editor before we&#8217;ve got the main part of it working (we may do some tweaking later).  We need to:</p>
<ul>
<li>add the Ok and Cancel buttons back; and</li>
<li>when someone clicks Ok, we need to update the server.properties file</li>
</ul>
<p>We&#8217;re doing the first of these today. We <a href="http://python4kids.wordpress.com/2012/03/06/minecraft-config-editor-tkinter-text-widget-and-frame/">saw earlier</a> how to do the Ok and Cancel <em>buttons</em>, although at the time we didn&#8217;t actually put any meat in the functions they called.  So, let&#8217;s fill that out now.  For Cancel, we are just going to quit the editor without making any changes &#8211; that&#8217;s pretty easy.  For the Ok <em>button</em> though, we&#8217;re going to have to:</p>
<ol>
<li>somehow read all of the values from the screen (since we don&#8217;t know which ones have been changed we need to read them all);</li>
<li>make a backup of the server.properties file</li>
<li>write all of the key:value pairs to the new server.properties file.</li>
</ol>
<p>Unlike <em>variables</em>, <em>widgets</em> are not the same as what is stored in them.  If we have an <em>Entry</em> <em>widget</em> called <em>E</em> and we want to store what has been typed there in a <em>variable</em> called <em>text</em> we can&#8217;t just write<em> text = E</em>.   This is because <em>E</em> is not a <em>variable</em> as we understand it.  Actually, <em>E</em> is an <em>instance</em> of a <em>class. </em> This would just make another reference to the same<em> Entry widget</em> with the name <em>text. </em> Rather, we want to &#8220;get&#8221; the current value of the text entered into <em>E</em>.  It turns out that the <em>Entry widget</em> has a <em>method</em> (called <em>get()</em>) which gets that text for you.</p>
<p><pre class="brush: python;">
&gt;&gt;&gt; from Tkinter import *
&gt;&gt;&gt; E = Entry()  # this should pop up a Tkinter window
&gt;&gt;&gt; E.pack()  # the widget should appear in your Tkinter window now
&gt;&gt;&gt; type(E)
&lt;type 'instance'&gt;
&gt;&gt;&gt; type(Entry)
&lt;type 'classobj'&gt;
&gt;&gt;&gt; text = E
&gt;&gt;&gt; type(text)
&lt;type 'instance'&gt;
&gt;&gt;&gt; print text
.140543131462184
&gt;&gt;&gt; # now type &quot;Hi P4K!&quot; in the entry widget
...
&gt;&gt;&gt; text = E.get()
&gt;&gt;&gt; print text
Hi P4K!
&gt;&gt;&gt; # now add &quot; - Again&quot; to the end of the entry widget (leave the &quot;Hi P4K!&quot; there)
...
&gt;&gt;&gt; text = E.get()
&gt;&gt;&gt; print text
Hi P4K! - Again
&gt;&gt;&gt; # you can also print the value which you get() without storing it first:
...
&gt;&gt;&gt; print E.get()
Hi P4K! - Again
</pre></p>
<p>So what we&#8217;re going to do in our code is <em>get()</em> all these edited values when someone clicks &#8220;Ok&#8221;.  We could do that directly, for example by finding the relevant <em>guiConfigItem</em> and calling the <em>get()</em> method on the <em>valueEntry</em> <em>attribute</em> of that item.   That would also mean we&#8217;d have to make a copy of the key for that item and then combine them together with &#8220;=&#8221; before we wrote them to the server.properties file.  This would mean that logic which is relevant to the configItem <em>class</em> would be stored somewhere other than inside the <em>class -</em> which rather defeats the purpose of having a <em>class</em> to keep track of these things.  Instead, we&#8217;re going to add a <em>method</em> to the <em>guiConfigItem</em> class which updates the values it has stored.  That turns out to be pretty easy:</p>
<p><pre class="brush: python;">
  def update(self):
    ''' Get the value which is currently in the Entry widget and save it to configVal'''
    if self.isTrueFalse:
      '''if isTrueFalse is True, then we should only have the values 'true' and 'false' in this
      Entry.  So, only update the configuration value if it is one of these two.  Otherwise, ignore it. '''
      spam = self.valueEntry.get()
      if spam in ['true','false']:
	self.configVal = spam
    else:
      '''this is not a variable which is limited to 'true' and 'false', so store the whole text'''
      self.configVal = self.valueEntry.get()

</pre></p>
<p>Note here that we are referencing the attribute configVal which is defined in the <em>parent</em> <em>class. </em> Also note that we&#8217;ve included a bit of logic here to ensure that those configuration values which start as &#8216;true&#8217; or &#8216;false&#8217; can only be &#8216;true&#8217; or &#8216;false&#8217;.  If you type something else into them it will be ignored.  It is sufficient here to just say <em>if self.isTrueFalse</em> rather than <em>if self.isTrueFalse is True</em> (the &#8220;is True&#8221; is redundant).</p>
<p>We also need a way to prepare the lines of the server.properties file to be printed or written to the file.  We do this by adding a <em>method</em> to the configItem <em>class</em> (since it doesn&#8217;t have anything to do with the graphical interface we don&#8217;t add it to the subclass):</p>
<p><pre class="brush: python;">
  def item2ConfigLine(self):
    if self.configKey==&quot;#&quot;:
      '''If the key is '#' then this is a comment, so don't include an '=' sign'''
      return &quot;%s%s&quot;%(self.configKey, self.configVal)
    else:
      '''otherwise, it has the form key=value'''
      return &quot;%s=%s&quot;%(self.configKey,self.configVal)
</pre></p>
<p>See<a href="http://python4kids.wordpress.com/2011/06/14/review-formatting-silly-sentences/"> this tutorial</a> for an explanation of the %s stuff&#8230;</p>
<p>We don&#8217;t have a way to test these methods out yet. So let&#8217;s hook up the Ok and Cancel <em>buttons.</em> The Ok button will run through each of the guiConfigItems and update it, then print out the configuration line. After all items have been processed this way, the program will exit. The cancel <em>button</em> will just exit without doing anything. So, we need to:<br />
1. create callbacks for each of the buttons,<br />
2. create a frame for the buttons to go in<br />
3. create the buttons, hooking up each of the buttons up to the callback<br />
4. pack the buttons, then, finally,<br />
5. pack the frame.<br />
These go before the<em> root.mainloop()</em> line.</p>
<p><pre class="brush: python;">
# 1. create callbacks for each of the buttons,
def okClicked():
  '''Get the edited values and write them to the file then quit'''
  for c in configLines:
    c.update()
    print c.item2ConfigLine()
  # have updated and printed each line, now exit
  exit()

def cancelClicked():
  '''Cancel edits and quit'''
  exit()

# 2. create a frame for the buttons to go in
bottomFrame = Frame(root)

# 3. create the buttons, hooking up each of the buttons up to the callback
okWidget = Button(bottomFrame, text= &quot;Ok&quot;, command = okClicked)
cancelWidget = Button(bottomFrame, text=&quot;Cancel&quot;, command = cancelClicked)

# 4. pack the buttons, then, finally,
okWidget.pack(side=LEFT)
cancelWidget.pack(side=RIGHT)
# 5. then pack the frame:
bottomFrame.pack(side=BOTTOM)
</pre></p>
<p>At the moment, the Ok <em>button</em> just prints out the values of the items. This is so that we can test how it is working before we let it go editing the actual file.</p>
<p>Here is the complete source code:</p>
<p><pre class="brush: python; collapse: true; light: false; toolbar: true;">
# -*- coding: utf-8 -*-

'''Minecraft config editor:
This is an editor for the Minecraft server.properties file.  It:
* opens the file server.properties
* reads, then closes the file
* parses each line by
-- stripping leading and trailing whitespace
-- if the line starts with &quot;#&quot;, marks it as a comment
-- splits the line into a key, value pair, with the pair separated by a &quot;=&quot; sign
-- if the value of the pair is either &quot;true&quot; or &quot;false&quot;, the entry is marked as a boolean (ie its only values are either true or false)
* displays each key, value entry on the screen allowing you to edit it
* renames the server.properties file to server.properties.bup (overwriting any existing file of that name from earlier edits)
* opens a new file called server.properties
* writes each of the entries to that new file
* closes the server.properties file.
'''

from Tkinter import *

class configItem(object):  # name of the class, it is based on an object called 'object'
  def __init__(self, line):# this is called each time an instance of the class is created
    line = line.strip()  # this removes any white space at the start or end of the line
    # if it starts with a # it's a comment so check for it
    if line[:1] == &quot;#&quot;:
       self.configKey = &quot;#&quot;
       self.configVal = line[1:]
    else:  # otherwise assume it's of the form x = y
       spam = line.split(&quot;=&quot;)
       self.configKey = spam[0]
       self.configVal = spam[1]
    # now check to see whether the config item takes only the values &quot;true&quot; and &quot;false&quot;
    if self.configVal.lower() in [&quot;true&quot;,&quot;false&quot;]:
       self.isTrueFalse = True
    else:
       self.isTrueFalse = False

  def item2ConfigLine(self):
    if self.configKey==&quot;#&quot;:
      '''If the key is '#' then this is a comment, so don't include an '=' sign'''
      return &quot;%s%s&quot;%(self.configKey, self.configVal)
    else:
      '''otherwise, it has the form key=value'''
      return &quot;%s=%s&quot;%(self.configKey,self.configVal)

class guiConfigItem(configItem):
  def __init__(self,line):
    super(guiConfigItem,self).__init__(line)  # run configItem's __init__ method
    self.frame = Frame()
    self.keyLabel = Label(self.frame, text = self.configKey)
    self.valueEntry = Entry(self.frame, width=&quot;60&quot;)
    self.valueEntry.insert(&quot;0&quot;,self.configVal)
    self.keyLabel.pack(side=LEFT )
    self.valueEntry.pack(side=RIGHT)
    self.frame.pack(side=TOP, fill=&quot;x&quot;)

  def update(self):
    ''' Get the value which is currently in the Entry widget and save it to configVal'''
    if self.isTrueFalse:
      '''if isTrueFalse is True, then we should only have the values 'true' and 'false' in this
      Entry.  So, only update the configuration value if it is one of these two.  Otherwise, ignore it. '''
      spam = self.valueEntry.get()
      if spam in ['true','false']:
	self.configVal = spam
    else:
      '''this is not a variable which is limited to 'true' and 'false', so store the whole text'''
      self.configVal = self.valueEntry.get()

# get data from the file

fileName = &quot;server.properties&quot;
fileObject = open(fileName,'rb')
fileData = fileObject.read()
fileObject.close()

root = Tk()
configLines = []

for line in fileData.split('\n'):  # this splits it into individual lines
    if line.strip()=='':
      continue
    configLines.append(guiConfigItem(line=line))

# 1. create callbacks for each of the buttons,
def okClicked():
  '''Get the edited values and write them to the file then quit'''
  for c in configLines:
    c.update()
    print c.item2ConfigLine()
  # have updated and printed each line, now exit
  exit()

def cancelClicked():
  '''Cancel edits and quit'''
  exit()

# 2. create a frame for the buttons to go in
bottomFrame = Frame(root)

# 3. create the buttons, hooking up each of the buttons up to the callback
okWidget = Button(bottomFrame, text= &quot;Ok&quot;, command = okClicked)
cancelWidget = Button(bottomFrame, text=&quot;Cancel&quot;, command = cancelClicked)

# 4. pack the buttons, then, finally,
okWidget.pack(side=LEFT)
cancelWidget.pack(side=RIGHT)
# 5. then pack the frame:
bottomFrame.pack(side=BOTTOM)

root.mainloop()
</pre></p>
<p><strong>Exercise: </strong>run the code and confirm that: (a) your edits are captured and printed out; (b) if you enter anything but &#8220;true&#8221; or &#8220;false&#8221; for an item that takes only true and false, then the edit is ignored; and (c) that if you change a true to a false or vice versa, that that edit is captured.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/python4kids.wordpress.com/436/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/python4kids.wordpress.com/436/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/python4kids.wordpress.com/436/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/python4kids.wordpress.com/436/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/python4kids.wordpress.com/436/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/python4kids.wordpress.com/436/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/python4kids.wordpress.com/436/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/python4kids.wordpress.com/436/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/python4kids.wordpress.com/436/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/python4kids.wordpress.com/436/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/python4kids.wordpress.com/436/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/python4kids.wordpress.com/436/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/python4kids.wordpress.com/436/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/python4kids.wordpress.com/436/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=python4kids.wordpress.com&blog=14472219&post=436&subd=python4kids&ref=&feed=1" width="1" height="1" />]]></description>
    <link><![CDATA[http://python4kids.wordpress.com/2012/03/21/almost-there-adding-methods-to-our-classes/]]></link>
    <pubDate>2012-05-22 05:39:52</pubDate>
  </item>
  <item>
    <title><![CDATA[Python 4 Kids: Minecraft config editor &#8211; Part, the Ultimate]]></title>
    <description><![CDATA[<p><a href="http://www.ibras.dk/montypython/episode06.htm">Boss     (unfolding big map across table; talking carefully) Right &#8230; this is the plan then. &#8230; At 10:52, I shall approach the counter and purchase a watch costing £5.18.3d. I shall then give the watch to you, Vic. You&#8217;ll go straight to Norman&#8217;s Garage in East Street. You lads continue back up here at 10:56 and we rendezvous in the back room at the Cow and Sickle, at 11:15. All right, any questions?<br />
Larry     We don&#8217;t seem to be doing anything illegal.<br />
Boss     What do you mean?<br />
Larry     Well &#8230; we&#8217;re paying for the watch.<br />
Boss     (patiently) Yes&#8230;<br />
Larry     (hesitating) Well&#8230; why are we paying for the watch?<br />
Boss     (heavily) They wouldn&#8217;t give it to us if we didn&#8217;t pay for it, would they&#8230; eh? </a></p>
<p>This is our final instalment <a href="http://en.wikipedia.org/wiki/Sic">[sic]</a> of our Minecraft config editor.   In the earlier tutorials we have done everything except actually updating the file.  Before we do update the file though, we need to make a backup of it, so it&#8217;s these two things that we&#8217;re going to do now.</p>
<p>All of the action will be in changing the behaviour of the &#8216;Ok&#8217; button so that it makes a copy of server.properties into a new file called server.properties.bup and then writes the updated data to the server.properties file.  There is a small amount of work in making a copy of the file so we are going to do it in a separate function.  The function is not very smart.  It reads all of the data from the existing file and then just writes it out to the new file:</p>
<p><pre class="brush: python;">
def backupFile(fileName):
  ''' Quick and dirty copy of file to fileName+&quot;.bup&quot; - might also use os.rename(), but behaviour of os.rename is platform dependent '''
  fileObject = open(fileName,'rb')
  fileData = fileObject.read()
  fileObject.close()
  fileObject= open(fileName+&quot;.bup&quot;,'wb')  # will overwrite if it exists
  fileObject.write(fileData)
  fileObject.close()
</pre></p>
<p>The <em>function</em> could also use the <em>rename() method</em> from the <a href="http://docs.python.org/library/os.html">os module</a>.  Unfortunately, this behaves differently depending on the operating system you are using, so to keep it simple I have avoided it.</p>
<p><strong>Exercise:</strong> Work out what this function is supposed to do, then confirm that it does it eg: start up a Python console, paste the definition in and then call the function with &#8220;server.properties&#8221; as a parameter.</p>
<p><strong>Extra Points</strong>: If you are on a Unix based system, use the <a href="http://en.wikipedia.org/wiki/Diff">diff</a> command to show the differences between the original and .bup (there shouldn&#8217;t be any).</p>
<p>With that done we can hook up the backup to the &#8216;Ok&#8217; callback, and also write the new data:</p>
<p><pre class="brush: python;">
def okClicked():
  '''Get the edited values and write them to the file then quit'''
  #TODO: add a confirmation dialog
  global fileName
  backupFile(fileName)
  dataToWrite = []
  for c in configLines:
    c.update()
    dataToWrite.append(c.item2ConfigLine())
  # have updated and printed each line, now exit
  fileObject = open(fileName,'wt')
  fileObject.write('\n'.join(dataToWrite)+'\n')
  # '\n' is technically not the newline character on Windows
  # but by default Python converts \n to the correct character on write
  # not sure if minecraft needs a final '\n', so included one just in case
  fileObject.close()
  exit()
</pre></p>
<p>Here we have introduced an <em>array</em> called <em>dataToWrite. </em> Where, in the last tute we just printed out the line, in this tute we are appending those lines to the <em>dataToWrite</em> array.  Then, once they have been accumulated, we open the server.properties file (clearing it) then write our new data into it.  Only one generation of backup is saved.</p>
<p>We have used the <em>global</em> statement here to use the value of the fileName variable.  This is a little messy, but is a consequence of how the program has evolved.</p>
<p>One of the things that you might include here is a confirmation step.  Before the data gets overwritten we might ask the user to confirm that they are going to write over their data, giving them a second chance if they clicked &#8220;Ok&#8221; by mistake.</p>
<p>Complete code here:</p>
<p><pre class="brush: python; collapse: true; light: false; toolbar: true;">
# -*- coding: utf-8 -*-

'''Minecraft config editor:
This is an editor for the Minecraft server.properties file.  It:
* opens the file server.properties
* reads, then closes the file
* parses each line by
-- stripping leading and trailing whitespace
-- if the line starts with &quot;#&quot;, marks it as a comment
-- splits the line into a key, value pair, with the pair separated by a &quot;=&quot; sign
-- if the value of the pair is either &quot;true&quot; or &quot;false&quot;, the entry is marked as a boolean (ie its only values are either true or false)
* displays each key, value entry on the screen allowing you to edit it
* renames the server.properties file to server.properties.bup (overwriting any existing file of that name from earlier edits)
* opens a new file called server.properties
* writes each of the entries to that new file
* closes the server.properties file.
'''

from Tkinter import *


class configItem(object):  # name of the class, it is based on an object called 'object'
  def __init__(self, line):# this is called each time an instance of the class is created
    line = line.strip()  # this removes any white space at the start or end of the line
    # if it starts with a # it's a comment so check for it
    if line[:1] == &quot;#&quot;:
       self.configKey = &quot;#&quot;
       self.configVal = line[1:]
    else:  # otherwise assume it's of the form x = y
       spam = line.split(&quot;=&quot;)
       self.configKey = spam[0]
       self.configVal = spam[1]
    # now check to see whether the config item takes only the values &quot;true&quot; and &quot;false&quot; 
    if self.configVal.lower() in [&quot;true&quot;,&quot;false&quot;]:
       self.isTrueFalse = True
    else:
       self.isTrueFalse = False
       
  def item2ConfigLine(self):
    if self.configKey==&quot;#&quot;:
      '''If the key is '#' then this is a comment, so don't include an '=' sign'''
      return &quot;%s%s&quot;%(self.configKey, self.configVal)
    else:
      '''otherwise, it has the form key=value'''
      return &quot;%s=%s&quot;%(self.configKey,self.configVal)
      
   

class guiConfigItem(configItem):
  def __init__(self,line):
    super(guiConfigItem,self).__init__(line)  # run configItem's __init__ method
    self.frame = Frame()
    self.keyLabel = Label(self.frame, text = self.configKey)
    self.valueEntry = Entry(self.frame, width=&quot;60&quot;)
    self.valueEntry.insert(&quot;0&quot;,self.configVal)
    self.keyLabel.pack(side=LEFT )
    self.valueEntry.pack(side=RIGHT)
    self.frame.pack(side=TOP, fill=&quot;x&quot;)
 
  def update(self):
    ''' Get the value which is currently in the Entry widget and save it to configVal'''
    if self.isTrueFalse:
      '''if isTrueFalse is True, then we should only have the values 'true' and 'false' in this
      Entry.  So, only update the configuration value if it is one of these two.  Otherwise, ignore it. '''
      spam = self.valueEntry.get()
      if spam in ['true','false']:
	self.configVal = spam
    else:
      '''this is not a variable which is limited to 'true' and 'false', so store the whole text'''
      self.configVal = self.valueEntry.get()
    
    
# get data from the file

fileName = &quot;ser_ver.properties&quot;
fileObject = open(fileName,'rb')
fileData = fileObject.read()
fileObject.close()



root = Tk()
configLines = []

for line in fileData.split('\n'):  # this splits it into individual lines
    if line.strip()=='':
      continue
    configLines.append(guiConfigItem(line=line))

# 1. create callbacks for each of the buttons, 
def okClicked():
  '''Get the edited values and write them to the file then quit'''
  #TODO: add a confirmation dialog
  global fileName
  backupFile(fileName)
  dataToWrite = []
  for c in configLines:
    c.update()
    dataToWrite.append(c.item2ConfigLine())
  # have updated and printed each line, now exit
  fileObject = open(fileName,'wt')
  fileObject.write('\n'.join(dataToWrite)+'\n')
  # '\n' is technically not the newline character on Windows
  # but by default Python converts \n to the correct character on write
  # not sure if minecraft needs a final '\n', so included one just in case
  fileObject.close()
  exit()

def backupFile(fileName):
  ''' Quick and dirty copy of file to fileName+&quot;.bup&quot; - might also use os.rename(), but behaviour of os.rename is platform dependent '''
  fileObject = open(fileName,'rb')
  fileData = fileObject.read()
  fileObject.close()
  fileObject= open(fileName+&quot;.bup&quot;,'wb')  # will overwrite if it exists
  fileObject.write(fileData)
  fileObject.close()

def cancelClicked():
  '''Cancel edits and quit'''
  exit()

# 2. create a frame for the buttons to go in
bottomFrame = Frame(root)

# 3. create the buttons, hooking up each of the buttons up to the callback
okWidget = Button(bottomFrame, text= &quot;Ok&quot;, command = okClicked)
cancelWidget = Button(bottomFrame, text=&quot;Cancel&quot;, command = cancelClicked)

# 4. pack the buttons, then, finally,
okWidget.pack(side=LEFT)
cancelWidget.pack(side=RIGHT) 
# 5. then pack the frame:
bottomFrame.pack(side=BOTTOM)

root.mainloop()


</pre></p>
<p><strong>Exercise:</strong> confirm that &#8220;Ok&#8221; saves your edits (open server.properties in a text editor or (<strong>extra points</strong>) write some Python to read and print the contents of the file) and that &#8220;Cancel&#8221; doesn&#8217;t.</p>
<p><strong>Comments:</strong></p>
<p>The code is a little messy because of how it has evolved in the course of explaining it.  Having code growing organically and getting messy is not unusual.  Every once in a while you need to stop and clean it up.  Cleaning it up can also allow you to restructure your code in ways you didn&#8217;t realise when you were writing it in the first place.</p>
<p>PS</p>
<p>My class names are naughty.  <a href="http://www.python.org/dev/peps/pep-0008/#class-names">They should start with a capital letter</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/python4kids.wordpress.com/453/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/python4kids.wordpress.com/453/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/python4kids.wordpress.com/453/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/python4kids.wordpress.com/453/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/python4kids.wordpress.com/453/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/python4kids.wordpress.com/453/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/python4kids.wordpress.com/453/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/python4kids.wordpress.com/453/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/python4kids.wordpress.com/453/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/python4kids.wordpress.com/453/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/python4kids.wordpress.com/453/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/python4kids.wordpress.com/453/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/python4kids.wordpress.com/453/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/python4kids.wordpress.com/453/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=python4kids.wordpress.com&blog=14472219&post=453&subd=python4kids&ref=&feed=1" width="1" height="1" />]]></description>
    <link><![CDATA[http://python4kids.wordpress.com/2012/03/28/minecraft-config-editor-part-the-ultimate/]]></link>
    <pubDate>2012-05-22 05:39:46</pubDate>
  </item>
  <item>
    <title><![CDATA[Python 4 Kids: Weird Binding Stuff]]></title>
    <description><![CDATA[<p><a href="http://www.ibras.dk/montypython/episode01.htm#8"><em>Voice Over     This man is Ernest Scribbler&#8230; writer of jokes. In a few moments, he will have written the funniest joke in the world&#8230; and, as a consequence, he will die &#8230; laughing.</em></a><br />
<a href="http://www.ibras.dk/montypython/episode01.htm#8"><em>    Ernest stops writing, pauses to look at what he has written&#8230; a smile slowly spreads across his face, turning very, very slowly to uncontrolled hysterical laughter&#8230; he staggers to his feet and reels across room helpless with mounting mirth and eventually collapses and dies on the floor.</em></a></p>
<p><strong>Summary</strong>: id(), copy, copy.copy(), copy.deepcopy()</p>
<p>A short tutorial this week on some oddities with the way Python stores and references (&#8220;binds to&#8221;) data.   You might remember, a long time ago, we talked about how, when we store data in a variable, <a href="http://python4kids.wordpress.com/2010/07/07/some-foundations-variables-and-stuff/">it&#8217;s like putting your stuff in a bucket so that you can access it later</a>.  Variables in Python actually turn out to be references to objects.   A side effect of this is that, in some cases, Python doesn&#8217;t work out how you think it will &#8211; typically this is where your <em>object</em> is a <em>list</em> or <em>dictionary</em> (actually any <em>object,</em> but you only notice this effect with compound objects) that you think you have copied, but you actually haven&#8217;t.</p>
<p>In particular, you can do this with &#8216;plain&#8217; variables:</p>
<pre> &gt;&gt;&gt; a = 5
 &gt;&gt;&gt; b = a
 &gt;&gt;&gt; a = 6
 &gt;&gt;&gt; b
 5</pre>
<p>You can also do this with lists:</p>
<pre> &gt;&gt;&gt; c = [1,2]
 &gt;&gt;&gt; d= c
 &gt;&gt;&gt; c =[5,6]
 &gt;&gt;&gt; d
 [1, 2]</pre>
<p>But there&#8217;s a gotcha with lists where you change one of the list&#8217;s entries:</p>
<pre> &gt;&gt;&gt; c= [1,2]
 &gt;&gt;&gt; d = c
 &gt;&gt;&gt; d
 [1, 2]
 &gt;&gt;&gt; c[0]=3
 &gt;&gt;&gt; d
 [3, 2]</pre>
<p>Can you see that, even though we only changed the first entry in the list <em>c</em> (that is, <em>c[0]</em>), the first entry of <em>d</em> has also changed?  That&#8217;s because there is an underlying list object that both <em>c</em> and <em>d</em> are pointing to.  That is, they are both pointing to the same thing.  In a sense they are both windows to the same room (the <em>list</em> object).  Looking in either window allows you to &#8220;see&#8221; the changes made in the room.   You can see that the objects are the same because you can check their location in memory using the<em> id()</em> function which is built in to Python (try <em>help(id)</em>):</p>
<pre> &gt;&gt;&gt; id(c)
 139636641421288
 &gt;&gt;&gt; id(d)
 139636641421288
 &gt;&gt;&gt; id(c) == id(d)
 True</pre>
<p>The number (139636641421288) is where in the computer&#8217;s memory the object is stored.  It will change, probably each time you run the program.  If we assign a different <em>list</em> to <em>d</em>, it will have a different <em>id</em>, even though the <em>values</em> in the <em>list </em>are the same:</p>
<pre> &gt;&gt;&gt; d = [3,2]       # note this new list has the same values as the old one
 &gt;&gt;&gt; id(c) == id(d)
 False
 &gt;&gt;&gt; id(d)
 139636640593824
 &gt;&gt;&gt;</pre>
<p>We can see that this other list is stored in a different location because the <em>id()</em> of the <em>lists</em> is different.  It turns out that this referencing behaviour is actually what you want to happen in most cases.  However, every so often you want your <em>lists</em> to be separate.  For that there is a special <em>module</em> called <em>copy. </em> The <em>copy</em> <em>module</em> has a <em>method</em> (also called <em>copy)</em> which allows you to <em>copy</em> across the <em>values</em> of an <em>object,</em> rather than simply referencing (called &#8220;<em>binding</em>&#8220;) to an existing <em>object:</em></p>
<pre>&gt;&gt;&gt; import copy
&gt;&gt;&gt; d = copy.copy(c)
&gt;&gt;&gt; d
[3, 2]
&gt;&gt;&gt; c[0]=1
&gt;&gt;&gt; d
[3, 2]
&gt;&gt;&gt; c
[1, 2]</pre>
<p>When you use <em>copy.copy()</em> the two objects will be separate and can be used independently.  Changes to one won&#8217;t show up in the other.  Where a compound object like a list or a dictionary has values which themselves are compound objects &#8211; for example a <em>list</em> where each entry in the <em>list</em> is itself a <em>list</em> &#8211; use the <em>copy.deepcopy()</em> method.   Depending on the complexity of your objects <em>deepcopy()</em> is not guaranteed to work (objects which refer to themselves somehow can cause a problem), but generally you will be fine.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/python4kids.wordpress.com/471/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/python4kids.wordpress.com/471/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/python4kids.wordpress.com/471/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/python4kids.wordpress.com/471/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/python4kids.wordpress.com/471/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/python4kids.wordpress.com/471/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/python4kids.wordpress.com/471/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/python4kids.wordpress.com/471/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/python4kids.wordpress.com/471/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/python4kids.wordpress.com/471/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/python4kids.wordpress.com/471/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/python4kids.wordpress.com/471/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/python4kids.wordpress.com/471/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/python4kids.wordpress.com/471/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=python4kids.wordpress.com&blog=14472219&post=471&subd=python4kids&ref=&feed=1" width="1" height="1" />]]></description>
    <link><![CDATA[http://python4kids.wordpress.com/2012/05/22/weird-binding-stuff/]]></link>
    <pubDate>2012-05-22 05:39:41</pubDate>
  </item>
  <item>
    <title><![CDATA[Mike Driscoll: Python on Windows: How to Get Set Up to Help with Core Development]]></title>
    <description><![CDATA[<p>I was reading Hynek Schlawack&#8217;s excellent <a href="http://hynek.me/articles/my-road-to-the-python-commit-bit/" target="_blank">article </a>on becoming a Python core developer and decided to find out just how hard it would be to get set up on my machine so that I could be ready to do core development myself, should I ever get the honor of being a part of the team. Since I run on Windows the most, I&#8217;m just going to talk about how I got set up for that OS. I&#8217;ve been thinking about trying to help with core development for a while anyway, so now&#8217;s as good a time as any. Let&#8217;s find out just how easy or hard the setting up process is!<span id="more-2330"></span></p>
<h3>What You&#8217;ll Need</h3>
<p>To get up and running as a developer of Python on Windows, you&#8217;ll need a <a href="http://mercurial.selenic.com/downloads/" target="_blank">Mercurial client</a> to download Python, update and create patches. You can use a command-line tool or you can get TortoiseHg, a shell GUI. Once you have that configured correctly, you can do a </p>
<p><code><br />
hg clone http://hg.python.org/cpython<br />
</code></p>
<p>Or use Tortoise to check out the repository. This will get you the latest Python 3.x version. If you want to help with a maintenance release, then you&#8217;ll want to read the <a href="http://docs.python.org/devguide/setup.html#setup" target="_blank">documentation</a>. The last major tool you&#8217;ll need is a compiler and the one that&#8217;s needed for the latest Python is Microsoft Visual Studio 2010. Fortunately, you don&#8217;t need to purchase the whole thing. In fact, you can just get the <a href="http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express" target="_blank">Express version of Visual C++ 2010</a> and you&#8217;ll be good to go. Note that this tool is not lightweight and ends up taking over one gigabyte of space on disc. Sad, but true. </p>
<h3>Compiling Python on Windows 7</h3>
<p>As you may have guessed, we&#8217;ll be doing the compiling of Python on Windows 7. I have Windows XP too, but that OS is practically dead now, so I&#8217;m not going to cover it. I doubt it&#8217;s much different anyway. Regardless, according to the dev guide <a href="http://docs.python.org/devguide/setup.html#windows" target="_blank">documentation</a>, you need to go into the repo that you just created on your machine and go into the <strong>PCBuild</strong> folder. Then find the <strong>pcbuild.sln</strong> file and run it with your new Visual Studio C++ application. You may see a warning from it about how the Express version doesn&#8217;t support Solutions, but just ignore that. Once the project is loaded, go into the <strong>Debug</strong> menu and select <strong>Build Solution</strong>. Oddly enough, the official docs say to go into the <strong>Build</strong> menu, NOT the Debug menu, but my copy doesn&#8217;t have a Build menu to choose from.</p>
<p>When I ran the build I got the following result at the end:</p>
<p><code><br />
========== Build: 20 succeeded, 8 failed, 0 up-to-date, 3 skipped ==========<br />
</code></p>
<p>Looking through the log, it looks like it was unable to find the header files for sqlite3 and tcl and it had some issues with the bzip lib. It also complained that I don&#8217;t have ActivePerl / openssh installed. However, it still compiled Python and I had a fresh <strong>python_d.exe</strong> file in my PCBuild folder that I could run. I ran it by double-clicking it, but you can also run it from within Visual Studio using F5 or by going to the <strong>Debug</strong> menu and clicking <strong>Start Debugging</strong>. </p>
<p><a href="http://www.blog.pythonlibrary.org/wp-content/uploads/2012/05/pycore.png"><img src="http://www.blog.pythonlibrary.org/wp-content/uploads/2012/05/pycore-300x195.png" alt="" title="pycore" width="300" height="195" class="aligncenter size-medium wp-image-2338" /></a></p>
<p>I think at this point, I&#8217;m ready to figure out how to create a patch. If I do, I may try patching that messed up documentation so that people won&#8217;t spend time looking for a non-existent menu. Then I&#8217;ll write an article about how to submit a patch and use the issue tracker system for Python. </p>
<h3>Related Reading</h3>
<ul>
<li>Python 101: <a href="http://www.blog.pythonlibrary.org/2011/11/24/python-101-setting-up-python-on-windows/" target="_blank">Setting up Python on Windows</a></li>
<li><a href="http://jessenoller.com/2009/02/04/a-brief-introduction-to-python-core-development-completely-different/" target="_blank">A (brief) introduction to Python-Core development</a></li>
<li>Contribution <a href="http://jessenoller.com/2011/05/05/on-contribution/" target="_blank">article</a></li>
<li><a href="http://jessenoller.com/2011/04/05/python-core-mentorship-up-and-running/" target="_blank">Python Core Mentorship program</a></li>
</ul>]]></description>
    <link><![CDATA[http://www.blog.pythonlibrary.org/2012/05/21/python-on-windows-how-to-get-set-up-to-help-with-core-development/]]></link>
    <pubDate>2012-05-22 02:31:23</pubDate>
  </item>
  <item>
    <title><![CDATA[John Cook: Using SciPy with IronPython]]></title>
    <description><![CDATA[<p>Three years ago I wrote a <a href="http://www.johndcook.com/blog/2009/02/26/ironpython-is-a-one-way-gate/">post</a> about my disappointment using SciPy with IronPython. A lot has changed since then, so I thought I&#8217;d write a short follow-up post.</p>
<p>To install NumPy and SciPy for use with IronPython, follow the instructions <a href="http://www.enthought.com/repo/.iron/">here</a>. After installation, NumPy works as expected.</p>
<p>There is one small gotcha with SciPy. To use SciPy with IronPython, start <code>ipy</code> with the command line argument <code>-X:Frames</code>. Then you can use SciPy as you would from CPython. For example.</p>
<pre>c:\&gt; ipy -X:Frames
&gt;&gt;&gt; import scipy as sp
&gt;&gt;&gt; sp.pi
3.141592653589793</pre>
<p>Without the <code>-X:Frames</code> option you&#8217;ll get an error when you try to import <code>scipy</code>.</p>
<pre>AttributeError: 'module' object has no attribute '_getframe'</pre>
<p>According to <a href="http://pytools.codeplex.com/discussions/259192">this page</a>,</p>
<blockquote><p>The issue is that SciPy makes use of the CPython API for inspecting the current stack frame which IronPython doesn&#8217;t enable by default because of a small runtime performance hit. You can turn on this functionality by passing the command line argument &#8220;-X:Frames&#8221; to on the command line.</p></blockquote>]]></description>
    <link><![CDATA[http://www.johndcook.com/blog/2012/05/21/using-scipy-with-ironpython/]]></link>
    <pubDate>2012-05-22 02:26:31</pubDate>
  </item>
  <item>
    <title><![CDATA[Eli Bendersky: grep through code history with Git, Mercurial or SVN]]></title>
    <description><![CDATA[<p>A problem that sometimes comes up with source-controlled code is to find a revision in which some line was deleted, or otherwise modified in a way that <tt class="docutils literal">blame</tt> can&#8217;t decipher. In other words, we want to grep over all revisions of some file to know which revisions contain a certain pattern. Note that the goal is not to search in the commit log (which is trivial), but rather in the code itself.</p>
<p>Well, if you&#8217;re using Mercurial or Git, you&#8217;re lucky because both provide built-in methods for doing this.</p>
<p>With Mercurial, use <tt class="docutils literal">hg grep</tt>.</p>
<p>With Git, you can either use <tt class="docutils literal">git grep</tt> in conjunction with <tt class="docutils literal">git <span class="pre">rev-list</span></tt>, or <tt class="docutils literal">git log <span class="pre">-S</span></tt> (more details in this <a class="reference external" href="http://stackoverflow.com/questions/2928584/how-to-grep-in-the-git-history">SO thread</a>).</p>
<p>What about Subversion, though? SVN, to the best of my knowledge, does not have this functionality built-in. Moreover, SVN&#8217;s design makes this task inherently slow because no revisions past the last one are actually kept on your machine (unless the repository is local) and you have to ask the server for each revision. That&#8217;s a lot of network traffic.</p>
<p>That said, if you&#8217;re willing to tolerate the slowness (and sometimes there&#8217;s no choice!), then the following script &#8211; <tt class="docutils literal">svnrevgrep</tt> &#8211; makes it as simple as with Git or Mercurial:</p>
<div class="highlight">
<pre><span>import</span> <span>re</span>, <span>sys</span>, <span>subprocess</span>

<span>def</span> <span>run_command</span>(cmd):
    <span>&quot;&quot;&quot; Run shell command, return its stdout output.</span>
<span>    &quot;&quot;&quot;</span>
    <span>return</span> subprocess.check_output(cmd.split(), universal_newlines=<span>True</span>)

<span>def</span> <span>svnrevgrep</span>(filename, s):
    <span>&quot;&quot;&quot; Go over all revisions of filename, checking if s can be found</span>
<span>        in them.</span>
<span>    &quot;&quot;&quot;</span>
    log = run_command(<span>'svn log '</span> + filename)
    <span>for</span> ver <span>in</span> re.findall(<span>'r\d+'</span>, log, flags=re.MULTILINE):
        cmd = <span>'svn cat -r %s %s'</span> % (ver.rstrip(<span>'r'</span>), filename)
        contents = run_command(cmd)
        <span>print</span>(<span>'%s: %s'</span> % (ver, <span>'found'</span> <span>if</span> re.search(s, contents)
                                       <span>else</span> <span>'not found'</span>))
<span>if</span> __name__ == <span>'__main__'</span>:
    <span>if</span> <span>len</span>(sys.argv) != <span>3</span>:
        <span>print</span>(<span>'Usage: %s &lt;path&gt; &lt;regex&gt;'</span> % sys.argv[<span>0</span>])
    <span>else</span>:
        svnrevgrep(sys.argv[<span>1</span>], sys.argv[<span>2</span>])
</pre>
</div>
<p>It basically goes over all revisions of the file starting with the most recent one and looks for the pattern.</p>
<p>Note that while one could imagine using some kind of binary searching to find the first revision in which the regex appears (or doesn&#8217;t), this won&#8217;t work in the general case because code sometimes is added, then deleted, then re-added, then deleted again (this happens when refactoring or when reverting problematic commits).</p>
<p>Finally, if you find yourself doing the above frequently for a given repository, you may be better off with:</p>
<div class="highlight">
<pre>git svn clone &lt;path&gt;
git grep &lt;...&gt;
</pre>
</div>
<img src="http://eli.thegreenplace.net/?ak_action=api_record_view&id=2867&type=feed" alt="" />

<p>Related posts:<ol><li><a href="http://eli.thegreenplace.net/2011/03/18/python-development-switches-to-mercurial-source-control/" rel="bookmark" title="Permanent Link: Python development switches to Mercurial source control">Python development switches to Mercurial source control</a> <small>The official CPython core development team has finally switched from...</small></li><li><a href="http://eli.thegreenplace.net/2010/05/22/migrating-my-personal-projects-to-mercurial/" rel="bookmark" title="Permanent Link: Migrating my personal projects to Mercurial">Migrating my personal projects to Mercurial</a> <small> Introduction My first acquaintance with version control was soon...</small></li></ol></p>]]></description>
    <link><![CDATA[http://eli.thegreenplace.net/2012/05/22/grep-through-code-history-with-git-mercurial-or-svn/]]></link>
    <pubDate>2012-05-22 01:51:17</pubDate>
  </item>
  <item>
    <title><![CDATA[CubicWeb: Thoughts on CubicWeb 4.0]]></title>
    <description><![CDATA[<div><p>This is a fairly technical post talking about the structural changes I would like to see in CubicWeb's near future. Let's call that CubicWeb 4.0! It also drafts ideas on how to go from here to there. Draft, really. But that will eventually turn into a nice roadmap hopefully.</p>
<div class="section" id="the-great-simplification">
<h3><a>The great simplification</a></h3>
<p>Some parts of cubicweb are sometimes too hairy for different reasons (some good,
most bad). This participates in the difficulty to get started quickly. The goal of CubicWeb 4.0 should be to make things simpler :</p>
<ul class="simple">
<li>Fix some bad old design.</li>
<li>Stop reinventing the wheel and use widely used libraries in the Python Web
World. This extends to benefitting from state of the art libraries to build nice
and flexible UI such as Bootstrap, on top of the JQuery foundations (which could
become as prominent as the Python standard library in CubicWeb, the development team should get
ready for it).</li>
<li>If there is a best way to do something, just do it and refrain from providing configurability and options.</li>
</ul>
</div>
<div class="section" id="on-the-road-to-bootstrap">
<h3><a>On the road to Bootstrap</a></h3>
<p>First, a few simple things could be done to simplify the UI code:</p>
<ul class="simple">
<li>drop xhtml support: always return text/html content type, stop bothering
with this stillborn stuff and use html5</li>
<li>move away everything that should not be in the framework: calendar?, embedding,
igeocodable, isioc, massmailing, owl?, rdf?, timeline, timetable?, treeview?,
vcard, wdoc?, xbel, xmlrss?</li>
</ul>
<p>Then we should probably move the default UI into some cubes (i.e. the content of
cw.web.views and cw.web.data). Besides making the move to Bootstrap easier, this
should also have the benefit of making clearer that this is the default way to
build an (automatic) UI in CubicWeb, but one may use other, more usual,
strategies (such as using a template language).</p>
<p>At a first glance, we should start with the following core cubes:</p>
<ul class="simple">
<li><cite>corelayout</cite>, the default interface layout and generic components. Modules to
backport there: application (not an appobject yet), basetemplates, error,
boxes, basecomponents, facets, ibreadcrumbs, navigation, undohistory.</li>
<li><cite>coreviews</cite>, the default generic views and forms. Modules to backport there:
actions, ajaxedit, baseviews, autoform, dotgraphview, editcontroller,
editforms, editviews, forms, formrenderers, primary, json, pyviews, tableview,
reledit, tabs.</li>
<li><cite>corebackoffice</cite>, the concrete views for the default back-office that let you
handle users, sources, debugging, etc. through the web. Modules to backport
here: cwuser, debug, bookmark, cwproperties, cwsources, emailaddress,
management, schema, startup, workflow.</li>
<li><cite>coreservices</cite>, the various services, not directly related to display of
something. Modules to backport here: ajaxcontroller, apacherewrite,
authentication, basecontrollers, csvexport, idownloadable, magicsearch,
sessions, sparql, sessions, staticcontrollers, urlpublishing, urlrewrite.</li>
</ul>
<p>This is a first draft that will need some adjustements. Some of the listed
modules should be split (e.g. actions, boxes,) and their content moved to
different core cubes. Also some modules in <cite>cubicweb.web</cite> packages may be moved
to the relevant cube.</p>
<p>Each cube should provide an interface so that one could replace it with another
one. For instance, move from the default <cite>coreviews</cite> and <cite>corelayout</cite> cube to
bootstrap based ones. This should allow a nice migration path from the current UI
to a Bootstrap based UI. Bootstrap should probably be introduced bottom-up: start
using it for tables, lists, etc. then go up until the layout defined in the main
template. The <a class="reference" href="http://orbui.com/">Orbui</a> experience should greatly help us by pointing at hot spots
that will have to be tackled, as well as by providing a nice code base from which
we should start.</p>
<p>Regarding current implementation, we should take care that Contextual components
are a powerful way to build &quot;pluggable&quot; UI, but we should probably add an
intermediate layer that would make more obvious / explicit:</p>
<ul class="simple">
<li>what the available components are</li>
<li>what the available slots are</li>
<li>which component should go in which slot when possible</li>
</ul>
<p>Also at some point, we should take care to separate view's logic from HTML
generation: our experience with client works shows that a common need is to use
the logic but produce a different HTML. Though we should wait for more use of
Bootstrap and related HTML simplification to see if the CSS power doesn't
somewhat fulfill that need.</p>
</div>
<div class="section" id="on-the-road-to-wsgi-and-related">
<h3><a>On the road to WSGI and related</a></h3>
<p>For the record regarding WSGI:</p>
<ul class="simple">
<li><a class="reference" href="http://mongrel2.org/">http://mongrel2.org/</a></li>
<li><a class="reference" href="http://projects.unbit.it/uwsgi/">http://projects.unbit.it/uwsgi/</a></li>
<li><a class="reference" href="http://wiki.nginx.org/NgxWSGIModule">http://wiki.nginx.org/NgxWSGIModule</a></li>
</ul>
<p>At some point, the whole <cite>cw.etwist</cite> package should be dropped in favor of <cite>cw.wsgi</cite>.</p>
<div class="section" id="werkzeug">
<h4><a>Werkzeug</a></h4>
<p><a class="reference" href="http://werkzeug.pocoo.org/">http://werkzeug.pocoo.org/</a></p>
<p>The Werkzeug framework sounds like a good candidate to use as a library that
would replace/simplify the request, httpcache, session, authentication (maybe
more) modules as well as the wsgi package. It sounds like the right candidate for
the following reasons:</p>
<ul class="simple">
<li>it's a non-intrusive WSGI library, not a web framework,</li>
<li>it's used by fairly popular frameworks (<a class="reference" href="http://www.openerp.com/community">openerp</a>, <a class="reference" href="http://flask.pocoo.org/">flask</a>),</li>
<li>I'm +1 on A. Ronacher idea of a common request implementation for python web
frameworks, let's experiment and promote this idea.</li>
</ul>
</div>
<div class="section" id="route-url-handling">
<h4><a>Route (URL handling)</a></h4>
<p>Investigate URL routing modules as a replacement for urlpublishing, urlrewrite and
apacherewrite.</p>
<p>Candidates are :</p>
<ul class="simple">
<li><cite>werkzeug.routing</cite>, which has noticable pros: celebrated by A. Martelli,
provided by an already-in-wishlist library, URL routing <em>AND</em> generation.</li>
<li><cite>routes</cite> (<a class="reference" href="http://routes.readthedocs.org/en/latest/">http://routes.readthedocs.org/en/latest/</a>), pros: used by pylons,
features conditional matching based on domain, cookies, HTTP method... and
sub-domain support.</li>
<li><cite>selector</cite> (<a class="reference" href="http://lukearno.com/projects/selector/">http://lukearno.com/projects/selector/</a>)</li>
</ul>
<p>I've to say I'm somewhat impatient to find some time to give a try to
<cite>werkzeug.routing</cite>. IMO, used well, that may introduce a structural change that
would make things much easier to understand and configure properly.</p>
</div>
</div>
<div class="section" id="on-the-road-to-proper-tasks-management">
<h3><a>On the road to proper tasks management</a></h3>
<p>The current looping task / repo thread mecanism is used for various sort of
things and has several problems:</p>
<ul class="simple">
<li>tasks don't behave similarly in a multi-instances configuration (some should
be executed in a single instance, some in a subset); the tasks system has been
originally written in a single instance context; as of today this is (sometimes)
handled using configuration options (that will have to be properly set in each
instance configuration file);</li>
<li>tasks is a repository only api but we also need web-side tasks;</li>
<li>there is probably some abuse of the system that may lead to unnecessary
resources usage.</li>
</ul>
<p>Analyzing a sample <a class="reference" href="http://www.logilab.org/">http://www.logilab.org/</a> instance, below are the running looping
task by categories. Tasks that have to run on each web instance:</p>
<ul class="simple">
<li><cite>clean_sessions</cite>, automatically closes unused repository sessions. Notice
<cite>cw.etwist.server</cite> also records a twisted task to clean web sessions. Some
changes are imminent on this, they will be addressed in the upcoming refactoring session  (that will
become more and more necessary to move on several points listed here).</li>
<li><cite>regular_preview_dir_cleanup</cite> (<cite>preview</cite> cube), cleanup files in the
preview filesystem directory. Could be executed by a (some of the) web
instance(s) provided that the preview directory is shared.</li>
</ul>
<p>Tasks that should run on a single instance:</p>
<ul class="simple">
<li><cite>update_feeds</cite>, update copy based sources (e.g. datafeed, ldapfeed). Controlled
by 'synchronize' source configuration (persistent source attribute that may be
overridden by instance using <cite>CWSourceHostConfig</cite> entities)</li>
<li><cite>expire_dataimports</cite>, delete <cite>CWDataImport</cite> entities older than an amount of
time specified in the 'logs-lifetime' configuration option. <strong>Not controlled
yet</strong>.</li>
<li><cite>cleanup_auth_cookies</cite> (<em>rememberme</em> cube), delete <cite>CWAuthCookie</cite> entities
whose life-time is exhausted. <strong>Not controlled yet</strong>.</li>
<li><cite>cleaning_revocation_key</cite> (<em>forgotpwd</em> cube), delete <cite>Fpasswd</cite> entities with
past <cite>revocation_date</cite>. <strong>Not controlled yet</strong>.</li>
<li><cite>cleanup_plans</cite> (<em>narval</em> cube), delete <cite>Plan</cite> entities instance older than an
amount of time specified in the configuration. If 'plan-cleanup-delay' is set
to an empty value, the task isn't started.</li>
<li><cite>refresh_local_repo_caches</cite> (<em>vcsfile</em> cube), pull or clone vcs repositories
cache if the <cite>Repository</cite> entity ask to import_revision_content (hence web
instance should have up to date cache to display files content) or if
'repository-import' configuration option is set to 'yes'; import vcs repository
content as entities if 'repository-import' configuration option and it is
coming from the system source.</li>
</ul>
<p>Some deeper thinking is needed here so we can improve things. That includes
thinking about:</p>
<ul class="simple">
<li>the inter-instances messages bus based on zmq and introduced in 3.15,</li>
<li>the Celery project (<a class="reference" href="http://celeryproject.org/">http://celeryproject.org/</a>), an asynchronous task queue,
widely used and written in Python,</li>
</ul>
<p>Remember the more cw independent the tasks are, the better it is. Though we still want an
'all-integrated' approach, e.g. not relying on external configuration of Unix
specific tools such as CRON. Also we should see if a hard-dependency on Celery or
a similar tool could be avoided, and if not if it should be considered as a
problem (for devops).</p>
</div>
<div class="section" id="on-the-road-to-an-easier-configuration">
<h3><a>On the road to an easier configuration</a></h3>
<p>First, we should drop the different behaviour according to presence of a '.hg' in
cubicweb's directory. It currently changes the location where cubicweb external
resources (js, css, images, gettext catalogs) are searched for. Speaking of
implementation:</p>
<ul class="simple">
<li><cite>shared_dir</cite> returns the <cite>cubicweb.web</cite> package path instead of the path to the
<cite>shared</cite> cube,</li>
<li><cite>i18n_lib_dir</cite> returns the <cite>cubicweb/i18n</cite> directory path instead of the path to the
<cite>shared/i18n</cite> cube,</li>
<li><cite>migration_scripts_dir</cite> returns the <cite>cubicweb/misc/migration</cite> directory path
instead of <cite>share/cubicweb/migration</cite>.</li>
</ul>
<p>Moving web related objects as proposed in the Bootstrap section would resolve the
problem for the content <cite>web/data</cite> and most of <cite>i18n</cite> (though some messages
will remain and additional efforts will be needed here). By going further this
way, we may also clean up some schema code by moving <cite>cubicweb/schemas</cite> and
<cite>cubicweb/misc/migration</cite> to a cube (though only a small benefit is to be expected
here).</p>
<p>We should also have fewer environment variables... Let's see what we have today:</p>
<ul class="simple">
<li>CW_INSTANCES_DIR, where to look for instances configuration</li>
<li>CW_INSTANCES_DATA_DIR, where to look for instances persistent data files</li>
<li>CW_RUNTIME_DIR, where to look for instances run-time data files</li>
<li>CW_MODE, set to 'system' or 'user' will predefine above environment variables differently</li>
<li>CW_CUBES_PATH, additional directories where to look for cubes</li>
<li>CW_CUBES_DIR, location of the system 'cubes' directory</li>
<li>CW_INSTALL_PREFIX, installation prefix, from which we can compute path to 'etc', 'var', 'share', etc.</li>
</ul>
<p>I would propose the following changes:</p>
<ul class="simple">
<li>CW_INSTANCES_DIR is turned into CW_INSTANCES_PATH, and defaults to
~/etc/cubicweb.d if it exists and /etc/cubicweb.d (on Unix platforms) otherwise;</li>
<li>CW_INSTANCES_DATA_DIR and CW_RUNTIME_DIR are replaced by configuration file
options, with smart values generated at instance creation time;</li>
<li>the above change should make CW_MODE useless;</li>
<li>CW_CUBES_DIR is to be dropped, CW_CUBES_PATH should be enough;</li>
<li>regarding CW_INSTALL_PREFIX, I'm lacking experience with non-hg-or-debian
installations and don't know if this can be avoided or not.</li>
</ul>
<p>Last but not least (for the moment), the 'web' / 'repo' / 'all-in-one'
configurations, and the fact that the associated configuration file changes
stinks. Ideas to stop doing this:</p>
<ul class="simple">
<li>one configuration file per instance, with all options provided by installed
parts of the framework used by the application.</li>
<li>activate 'services' (or not): web server, repository, zmq server, pyro
server. Default services to be started are stored in the configuration file.</li>
</ul>
<p>There is probably more that can be done here (less configuration options?), but
that would already be a great step forward.</p>
</div>
<div class="section" id="on-the-road-to">
<h3><a>On the road to...</a></h3>
<p>The following projects should be investigated to see if we could benefit from them:</p>
<ul class="simple">
<li>Paste (<a class="reference" href="http://pythonpaste.org/">http://pythonpaste.org/</a>, Configuration and all)</li>
<li>Beaker (<a class="reference" href="http://beaker.readthedocs.org/en/latest/index.html">http://beaker.readthedocs.org/en/latest/index.html</a>, More on Session / cache handling than what will be found in Werkzeug?)</li>
<li>Pyramid's debug toolbar
(<a class="reference" href="http://docs.pylonsproject.org/projects/pyramid_debugtoolbar/en/latest/">http://docs.pylonsproject.org/projects/pyramid_debugtoolbar/en/latest/</a>). See
also <a class="reference" href="http://firelogger.binaryage.com/#python">http://firelogger.binaryage.com/#python</a>. Notice Werkzeug comes with an
integrated js console as well.</li>
<li>zc.buildout (Deployment)</li>
</ul>
</div>
<div class="section" id="discussion">
<h3><a>Discussion</a></h3>
<p>Remember the following goals: migration of legacy code should go smoothly. In a perfect world every application should be able to run with CubicWeb 4.0 until the backwards compatibility code is removed (and CubicWeb 4.0 will probably be released as 4.0 at that time).</p>
<p>Please provide feedbacks:</p>
<ul class="simple">
<li>do you think choices proposed above are good/bad choices? Why?</li>
<li>do you know some additional libraries that should be investigated?</li>
<li>do you have other changes in mind that could/should be done in cw 4.0?</li>
</ul>
</div></div>]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/cubicweborg/~3/TcdinjESViY/2356431]]></link>
    <pubDate>2012-05-21 16:04:00</pubDate>
  </item>
  <item>
    <title><![CDATA[Logilab: Mercurial 2.3 sprint, Day 1-2-3]]></title>
    <description><![CDATA[<div><p>I'm now back from Copenhagen were I attended the mercurial 2.3 sprint with twenty
other people. A huge amount of work was done in a very
friendly atmosphere.</p>
<p><strong>Regarding mercurial's core:</strong></p>
<ul class="simple">
<li><a class="reference" href="http://mercurial.selenic.com/wiki/Bookmarks/">Bookmark</a> behaviour was improved to get closer to named branch's behaviour.</li>
<li>Several performance improvements regarding branches and heads caches. The heads cache refactoring improves rebase performance on huge repository (thanks to <a class="reference" href="http://www.facebook.com/facebook">Facebook</a> and <a class="reference" href="http://www.atlassian.com">Atlassian</a>).</li>
<li>The concept I'm working on, <a class="reference" href="http://hg-lab.logilab.org/doc/mutable-history/html/">Obsolete markers</a>, was a highly discussed subject and is expected to get partly into the core in the near future. Thanks to my employer <a class="reference" href="http://www.logilab.fr/">Logilab</a> for paying me to work on this topic.</li>
</ul>
<ul class="simple">
<li>General code cleanup and lock validation.</li>
</ul>
<img alt="http://www.logilab.org/file/92956?vid=download" src="http://www.logilab.org/file/92956?vid=download" />
<p><strong>Regarding the bundled extension :</strong></p>
<ul class="simple">
<li>Some fixes where made to <a class="reference" href="http://mercurial.selenic.com/wiki/ProgressExtension">progress</a> which is now closer to getting into mercurial's core.</li>
<li><a class="reference" href="http://mercurial.selenic.com/wiki/HisteditExtension">Histedit</a> and <a class="reference" href="http://mercurial.selenic.com/wiki/KeyringExtension">keyring</a> extensions are scheduled to be shipped with mercurial.</li>
<li>Some old and unmaintained extensions (children, hgtk) are now deprecated.</li>
<li>The <a class="reference" href="http://mercurial.selenic.com/wiki/LargefilesExtension">LargeFile</a> extension got some new features (thanks to the folks from <a class="reference" href="http://unity3d.com/">Unity3D</a>)</li>
<li>Rebase will use the --detach flag by default in the next release.</li>
</ul>
<img alt="http://www.logilab.org/file/92958?vid=download" src="http://www.logilab.org/file/92958?vid=download" />
<p><strong>Regarding the project itself:</strong></p>
<ul class="simple">
<li>We now have a running <a class="reference" href="http://hgbuildbot.kublai.com/builders/Windows%202008%20R2%20hg%20tests">buildbot for Windows</a> (in addition to the runnable test
suite itself).</li>
<li>We migrated from round-up to <a class="reference" href="http://bz.selenic.com/">bugzilla</a>.</li>
</ul>
<img alt="http://www.logilab.org/file/92955?vid=download" src="http://www.logilab.org/file/92955?vid=download" />
<p><strong>Regarding other extensions:</strong></p>
<ul class="simple">
<li><a class="reference" href="http://mercurial.selenic.com/wiki/HgSubversion">hgsubversion</a> got a lot of bug fix (the harmonious image of the <a class="reference" href="http://www.google.com/intl/en/about/index.html">Google</a> staff
reviewing patches from the <a class="reference" href="http://www.facebook.com/facebook">Facebook</a> staff).</li>
<li><a class="reference" href="http://www.edlund.dk/en/about-edlund/">Edlund</a> released their <a class="reference" href="https://bitbucket.org/hstuart/repoman">repoman</a> tool to manage forests of repositories used in
multiple &quot;solutions&quot;.</li>
<li>A new <a class="reference" href="https://bitbucket.org/hstuart/hg-multiundo">multiundo</a> extension was written (thanks to <a class="reference" href="http://www.edlund.dk/en/about-edlund/">Edlund</a> and <a class="reference" href="http://www.wolfram.com/">Wolfram Research</a>).</li>
</ul>
<img alt="http://www.logilab.org/file/92959?vid=download" src="http://www.logilab.org/file/92959?vid=download" />
<p>And I'm probably forgetting some stuff.
Special thanks to <a class="reference" href="http://unity3d.com/">Unity3D</a> for hosting the sprint and providing power, network
and food during these 3 days.</p></div>]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/logilaborg_en/~3/Lu43E5sxn_Q/92961]]></link>
    <pubDate>2012-05-21 15:09:00</pubDate>
  </item>
  <item>
    <title><![CDATA[Kristján Valur: Killing a Stackless bug]]></title>
    <description><![CDATA[<p>What follows is an account of how I found and fixed an insidious bug in Stackless Python which has been there for years.  It&#8217;s one of those war stories.  Perhaps a bit long winded and technical and full of exaggerations as such stories tend to be.</p>
<h2>Background</h2>
<p>Some weeks ago, because of a problem in the client library we are using, I had to switch the http library we are using on the PS3 from using non-blocking IO to blocking. Previously, we were were issuing all the non-blocking calls, the &#8220;select&#8221; and the tasklet blocking / scheduling on the main thread. This is similar to how <a href="http://www.gevent.org/">gevent </a>and other such libraries do things. Switching to blocking calls, however, meant doing things on worker threads.</p>
<p>The approach we took was to implement a small pool of pyton workers which could execute arbitrary jobs. A new utility function, <em>stacklesslib.util.call_async()</em> then performed the asynchronous call by dispatching it to a worker thread. The idea of an <em>call_async()</em> is to have a different tasklet execute the callable while the caller blocks on a <em>channel</em>. The return value, or error, is then propagated to the originating tasklet using that channel. Stackless channels can be used to communicate between threads too. And synchronizing threads in stackless is even more conveninent than regular Python because there is stackless.atomic, which not only prevents involuntary scheduling of tasklets, it also prevents automatic yielding of the GIL (cPython folks, take note!)</p>
<p>This worked well, and has been running for some time. The drawback to this approach, of course, is that we now need to keep python threads around, consuming stack space. And Python needs a lot of stack.</p>
<h2>The problem</h2>
<p>The only problem was, that there appeared to be a bug present. One of our developers complained that sometimes, during long downloads, the http download function would return None, rather than the expected string chunk.</p>
<p>Now, this problem was hard to reproduce. It required a specific setup and geolocation was also an issue. This developer is in California, using servers in London. Hence, there ensued a somewhat prolonged interaction (hindered by badly overlapping time-zones) where I would provide him with modified .py files with instrumentation, and he would provide me with logs. We quickly determined, to my dismay, that apparently, sometimes a string was turning into None, while in transit trough a channel.send() to a channel.receive(). This was most distressing. Particularly because the channel in question was transporting data between threads and this particular functionality of stackless has not been as heavily used as the rest.</p>
<h2>Tracking it down</h2>
<p>So, I suspected a race condition of some sorts. But a careful review of the channel code and the scheduling code presented no obvious candidates. Also, the somehwat unpopular GIL was being used throughout, which if done correctly ensures that things work as expected.</p>
<p>To cut a long story short, by a lucky coincidence I managed to reproduce a different manifestation of the problem. In some cases, a simple interaction with a local HTTP server would cause this to happen.</p>
<p>When a channel sends data between tasklets, it is temporarily stored on the target tasklet&#8217;s &#8220;tempval&#8221; attribute. When the target wakes up, this is then taken and returned as the result from the &#8220;receive()&#8221; call. I was able to establish that after sending the data, the target tasklet did indeed hold the correct string value in its &#8220;tempval&#8221; attribute. I then needed to find out where and why it was disappearing from that place.</p>
<p>By adding instrumentation code to the stackless core, I established that this was happening in the last line of the following snippet:</p>
<pre class="brush: c">
PyObject *
slp_run_tasklet(void)
{
    PyThreadState *ts = PyThreadState_GET();
    PyObject *retval;

    if ( (ts-&gt;st.main == NULL) &amp;&amp; initialize_main_and_current()) {
        ts-&gt;frame = NULL;
        return NULL;
    }

    TASKLET_CLAIMVAL(ts-&gt;st.current, &amp;retval);
</pre>
<p>By setting a breakpoint, I was able to see that I was in the top level part of the &#8220;continue&#8221; bit of the &#8220;stack spilling&#8221; code</p>
<p>S<em>tack spilling</em> is a feature of stackless where the stack slicing mechanism is used to recycle a deep callstack. When it detects that the stack has grown beyond a certain limit, it is stored away, and a hard switch is done to the top again, where it continues its downwards crawl. This can help conserve stack address space, particularly on threads where the stack cannot grow dynamically.</p>
<p>So, something wrong with stack spilling, then.  But even so, this was unexpected. Why was stack spilling happening when data was being transmitted across a channel? Stack spilling normally occurs only when nesting regular .py code and other such things.</p>
<p>By setting a breakpoint at the right place, where the stack spilling code was being invoked, I finally arrived at this callstack:</p>
<blockquote><p>
Type Function<br />
PyObject* slp_eval_frame_newstack(PyFrameObject* f, int exc, PyObject* retval)<br />
PyObject* PyEval_EvalFrameEx_slp(PyFrameObject* f, int throwflag, PyObject* retval)<br />
PyObject* slp_frame_dispatch(PyFrameObject* f, PyFrameObject* stopframe, int exc, PyObject* retval)<br />
PyObject* PyEval_EvalCodeEx(PyCodeObject* co, PyObject* globals, PyObject* locals, PyObject** args, int argcount, PyObject** kws, int kwcount, PyObject** defs, int defcount, PyObject* closure)<br />
PyObject* function_call(PyObject* func, PyObject* arg, PyObject* kw)<br />
PyObject* PyObject_Call(PyObject* func, PyObject* arg, PyObject* kw)<br />
PyObject* PyObject_CallFunctionObjArgs(PyObject* callable)<br />
void PyObject_ClearWeakRefs(PyObject* object)<br />
void tasklet_dealloc(PyTaskletObject* t)<br />
void subtype_dealloc(PyObject* self)<br />
int slp_transfer(PyCStackObject** cstprev, PyCStackObject* cst, PyTaskletObject* prev)<br />
PyObject* slp_schedule_task(PyTaskletObject* prev, PyTaskletObject* next, int stackless, int* did_switch)<br />
PyObject* generic_channel_action(PyChannelObject* self, PyObject* arg, int dir, int stackless)<br />
PyObject* impl_channel_receive(PyChannelObject* self)<br />
PyObject* call_function(PyObject*** pp_stack, int oparg)
</p></blockquote>
<p>Notice the &#8220;subtype_dealloc&#8221;. This callstack indicates that in the channel receive code, after the hard switch back to the target tasklet, a Py_DECREF was causing side effects, which again caused stack spilling to occur. The place was this, in slp_transfer():</p>
<pre class="brush: c">
/* release any objects that needed to wait until after the switch. */
Py_CLEAR(ts-&gt;st.del_post_switch);
</pre>
<p>This is code that does cleanup after tasklet switch, such as releasing the last remaining reference of the previous tasklet.</p>
<p>So, the bug was clear then. It was twofold:</p>
<ol>
<li>A Py_CLEAR() after switching was not careful enough to store the current tasklet&#8217;s &#8220;tempval&#8221; out of harms way of any side-effects a Py_DECREF() might cause, and</li>
<li>Stack slicing itself, when it happened, clobbered the current tasklet&#8217;s &#8220;tempval&#8221;</li>
</ol>
<p>The bug was subsequently fixed by repairing stack spilling and spiriting &#8220;tempval&#8221; away during the Py_CLEAR() call.</p>
<h2>Post mortem</h2>
<p>The inter-thread communication turned out to be a red herring. The problem was caused by an unfortunate juxtaposition of channel communication, tasklet deletion, and stack spilling.<br />
But why had we not seen this before? I think it is largely due to the fact that stack spilling only rarely comes into play on regular platforms. On the PS3, we deliberately set the threshold low to conserve memory space. This is also not the first stack-spilling related bug we have seen on the PS3, but the first one for two years. Hopefully it will be the last.</p>
<p>Since this morning, the fix is in the stackless repository at <a href="http://hg.python.org/stackless">http://hg.python.org/stackless</a></p>]]></description>
    <link><![CDATA[http://blog.ccpgames.com/kristjan/2012/05/21/killing-a-stackless-bug/]]></link>
    <pubDate>2012-05-21 14:52:38</pubDate>
  </item>
  <item>
    <title><![CDATA[Andrew Dalke: Testing hard algorithms]]></title>
    <description><![CDATA[<p>

I developed software to find a maximum common subgraph (MCS) given a
set of molecules represented as a chemical graph. It's called <a href="https://bitbucket.org/dalke/fmcs">fmcs</a>. My previous three
essays were about the <a href="http://www.dalkescientific.com/writings/diary/archive/2012/05/12/mcs_background.html">background</a>
of the MCS problem, <a href="http://www.dalkescientific.com/writings/diary/archive/2012/05/13/fmcs.html">introducing fmcs</a>, and <a href="http://dalkescientific.com/writings/diary/archive/2012/05/13/mcs_chebi.html">an example of when MCS is used</a>.

</p><p>

What I didn't describe was the mental effort it took to develop this
program. This is the second time I've written code to find the
multiple structure MCS, and both times it took a couple of months and
put my head in a very strange place. You would think the second time
is easier, but it means that I spent more time adding features and
doing things that my first version couldn't begin to handle. (Did
someone just mutter "second system effect"? Pshaw!)

</p><p>

This time too I had a better understanding of the development process.
I think I know why it's so much harder than most of the software I
develop.

</p><p>

In this essay, I reflect on some of the reasons why this is a hard
problem to test and I consider how unit tests, or any other
incremental-based testing approach, are not well-suited to a certain
class of complex algorithm development. While unit tests can provide a
basic sanity check during development, they fail to provide the test
coverage which one might expect from applying them to algorithmically
simpler modules. Further, development methodologies built primarily on
unit tests, like test-first style test-driven development, aren't that
applicable. Instead, other methods, like system testing and a deep
understanding of the algorithm and possible problems, are
required. This strengthens my view, explored in 
<a href="http://www.dalkescientific.com/writings/diary/archive/2009/12/29/problems_with_tdd.html">Problems with TDD</a>
that "TDD is a weak method for developing those tests of confidence."


</p>
<h3>How would you implement an MCS algorithm?</h3>
<p>

Think about the problem for a moment. How would you write an algorithm
to find the largest common subgraph between two graphs?

</p><p>

Take your time. This really is a hard problem. I dug up some of the
early papers from the Journal of Computer Documentation. People ended
up simplifying the problem by, for example, not supporting rings.

</p><p>

Finished thinking?

</p><p>

You probably came up with a graph walking algorithm which tries
different match pairings and uses backtracking or lazy evaluation to
search all of graph space. The more mathemtically inlined might have
converted this into a maximum clique algorithm.

</p><p>

In both cases there are a lot of arbitrary decisions to make. Which
pairings should you investigate first? Are there times when you cann
prune the search space? Did you make any assumptions about the nature
of the chemical graph (eg, that it's <a href="http://dalkescientific.com/writings/diary/archive/2012/05/18/nonplanar_compounds.html">topologically a planar graph</a>)?

</p>
<h3>How would you test your MCS algorithm?</h3>
<p>

Back in the late 1990s, I almost never wrote automated tests,
and never wrote an extensive test suite. Nowadays I'm pretty thorough,
and use coverage-guided techniques to get good, extensive tests
through some semi-permanent API layer that will allow me to refactor
the internals without changing the tests.

</p><p>

I couldn't do that here.

</p><p>

There are a lot of heuristics, and some of them are only triggered
under unusual circumstances, after a bunch of combinitorial
possibilities. Outside of a few minor components, I couldn't figure
out how to write unit tests for the code.

</p><p>

I ended up pushing most of the testing into validation testing of the
complete system, which meant I wrote some 1,000+ lines of code
without strong testing. Moreover, I used a new approach to the MCS
problem, so the algorithm I was working on doesn't have the track
record of the standard clique-based or backtracking approaches.


</p><p>

So stress factors included not knowing if the algorithm would work,
and not being able to develop enough test cases to provide good
validation during development.

</p><p>

As a rule of thumb, it's easiest to fix bugs which are caught
early. Unit tests and evolutionary prototyping are two of the
techniques that people use to tighten the feedback loop between
specification, implementation, and valiation. I think another stress
factor is propotional to the size of the feedback loop.

</p>
<h2>What testing did I do?</h2>
<p>

I mean, I did have tests during development. I came up with a few
examples by hand, I did a substructure search of a large data set and
I verified that the MCS code found that substructure, but I know
that's not enough tests. I know this because after six weeks of
development and over 1000 lines of code, I spent another three weeks
doing a large amount of post-development testing, and found several
bugs. In the process of writing this essay I also found that four days
of that development work ended up making things slower, so I'll have
to remove it.

</p><p>

I did most of my tests based on the <a href="https://www.ebi.ac.uk/chembldb/">ChEMBL</a> data: 10,000 random
pairs of structures, the k=2, k=10, and k=100 nearest neighbors, and
the k&lt;=100 neighbors with similarities of at least 0.95, 0.9, and
0.8. I also did, at the end, tests based on the ChEBI structure
ontology. There were easily 20,000 different machine-generated test
cases, although in most cases I didn't know the expected results
beforehand.

</p>
<h2>What bugs did I find?</h2>
<p>

What bugs did I find? I think it's educational to characterize a few of them.

</p>
<h3>Typo caught by an assertion check</h3>
<p>

One of the simplest bugs was a poorly formatted string. I used "%d"
when I should have used ""%%%d". A bit of jargon for those in the
know; I generate SMARTS strings for the intermedate subgraphs. If
there are more than 9 open rings then the syntax goes from a single
digit closure number to a closure number like "%10". I forgot to
include the '%' for that case, and probably because the '%' was
already there for the format string.

</p><p>

This wasn't triggered by my random-pairs test nor my various
similarity-search based tests. Only when I ran through the ChEBI data,
did I get an assertion failure when RDKit refused to accept my SMARTS
string. That was the first time where I had a SMARTS with 10 unclosed
rings.

</p><p>

As it happens, this error could have been caught by a unit testing, as
some people practice unit tests. It's a four line function which takes
a string and a number. Testing it is trivial. I didn't test it because
I feel that testing directly against internal functions inhibits
refactoring. I prefer to test against higher-level, more stable APIs.

</p><p>

My view is that it's usually easy to come up with high-level test
cases which trigger a certain function call. But not in this case. The
MCS search algorithm, while deterministic, uses so many arbitrarily
defined values that I couldn't on my own come up with a test case with
at least 10 open ring closures. And even if I did, a new search
heuristic might change things so that only, say, 7 open ring closures
were needed.

</p><p>

I felt that my system testing and the assertion check would be
enough to identify if there was a problem, and it did. A low-level
unit test might have helped, especially as I still don't have a
specific test for that failure.

</p><p>

I think the right thing to do is add that failure as a specific test
case, and use monkey-patching to insert wrong code for a repeat of
that test case. The first one tests that the code is correct, and the
second tests that the test case is still exercising the code under
test.

</p>
<h3>Cross-validation testing</h3>
<p>

The first MCS papers are about as old as I am. Many people have
written implementions, although relatively few are are available to me
both at no cost and with no prohibitions on using it to develop a new
MCS algorithm. (Some commercial companies don't like people using
their software to write new software which is competitive to it, or
even to use their software for benchmark comparisons.)

</p><p>

I tested pairs of structures against <a href="http://www.ebi.ac.uk/thornton-srv/software/SMSD/">SMSD</a> and I
did more extenstive tests against <a href="http://ggasoftware.com/opensource/indigo">Indigo's</a> MCS
implementation.

</p><p>

This is cross-validation testing. It's a relatively rare technique
because the cost of producing multiple identical implementations
usually isn't worth the benefits. Even here the results aren't exactly
identical because of differences in how the toolkits perceive
chemistry, and more specifically, aromaticity. I ended up spending a
lot of investigation time staring at cases with different answers and
trying to figure out if it was a chemistry problem or an MCS algorithm
implementation problem.

</p><p>

I found the SMSD had a bug in one of its options, which I reported
back to the author. The code had been fixed internally but not pushed
to the outside world. Its default mode and fmcs matched quite well,
except for a couple of chemistry differences. The new version is out
now - I need to test it again.

</p><p>

The only problem I found in the Indigo code was a part of their setup
code which didn't check the timeout. That's also been fixed after I
reported it.

</p><p>

The cross-validation with Indigo found problems in my code. For
example, I was often getting smaller MCSes then Indigo. After looking
at them, I figured out that my code didn't correctly handle the case
when a molecule was fragmented after a bond was removed because its
bondtype wasn't in all of the structures.

</p><p>

Why didn't my hand-written test cases find it? None of them had a case
where there was a bond in the "middle" of a structure chosen as the
reference structure, and where the MCS was not in the first fragment.

</p><p>

My code usually got the right answer when using highly similar
structures, for obvious reasons. It was only the random pair testing
where the problem really stood out.

</p><p>

Could I create a simple unit test for this error? Perhaps, but it's
not easy. I don't know which of the two fragments will be first - it
depends on so many arbitrary decisions which could change as the
algorithm is improved. The only test I can think of for this was to
generate a diverse set of tests, make sure some fail if the code isn't
implemented correctly, record the results, and make sure that future
tests never find a worse (or better?) test case.

</p>
<h3>Bad heuristic to determine the maximum possible subgraph growth</h3>
<p>

Most of the MCS implementation is heuristics. There's a branch and
bound search, there's subgraph canonicalization to reduce the number
of substructure tests, and so on. Each of these is supposed to help
make the code faster.

</p><p>

One of the tests takes the current subgraph and the list of "outgoing"
bonds to see how much of the remainder of the graph is accessible for
growth from the current subgraph. The rest of the molecule might not
be accessible because it's on another fragment, but it also might not
be accessible due to an earlier decision to exclude certain parts of
the molecule from future growth. (My algorithm tests all subgraphs
which include a given bond, then all subgraph which don't include the
given bond.)

</p><p>

It took a couple of days to think of the algorithm, write the code,
and get it working. I then did the timing tests to find out it was 1%
faster, to get the same answers.

</p><p>

Does that mean my code worked? I only had a suspicion that the new
algorithm should be faster. Perhaps the overhead of searching for the
accessible atoms was too costly?

</p><p>

After looking at my implementation - a lot - I finally realized that I
told the algorithm to exclude the subgraph from consideration for
growth but had forgotten to also exclude the set of previously
excluded bonds from consideration. With two changed lines, the overall
performance doubled for the random-pairs case. Most of the time it's
faster and sometimes its slower, so it takes an aggregate of tests to
measure this correctly.

</p><p>

I don't think this heuristic could have been written as a unit
test. No, I take that back. It could have, but it would have required
some careful thought to set up. Not only was this part of the code not
"built for test", but setting up the right conditions requires a
mental understanding of the problem which I know I didn't have when I
was doing the development.

</p><p>

BTW, I am not saying that unit tests can't be used to measure
performance. Some algorithms have simple timing characteristics where
it's easy to say that the code must complete by a given time, or that
it must be at least twice as fast as a reference
implementation. Occasionally these tests will hiccup due to unusual
loads on the test machine, but not usually enough to be a problem.

</p><p>

Indeed, the fmcs code has some unit tests for the timeout code. I
found a pair of structures which takes over 10 seconds to find the
MCS, I set the timeout to 0.1 second, and assert that no more than 0.5
seconds elapsed during the function call. (I don't require a high
precision for this code.) I do worry though that future changes to the
MCS search code might speed things up by a faster of 20. On the other
hand, the effect of broken timeout code is very obvious when running
the validation suite, so I'm not going to worry about it.

</p><p>

As is widely acknowledged, this stretches the idea of a "unit test."
Unit tests are supposed to be fast; preferably several hundred or more
per second. The goal is that these tests run often, perhaps even after
every save. Stick in a few 0.1 second timeouts into the system and it
bogs everything down, which discourages people from running the tests
so often.

</p><p>

But let's go back to this new code. On average, over a large number of
tests, the performance is 50% faster. What's a good test case? Can I
pick one structure or a small set of structures? Does the speedup
occur only when there are large molecules? Only for molecules with
lots of internal symmetry?  Only for those which are easily
fragmented?

</p><p>

Only now, when writing this essay, did I find good test cases. When I
use a 10 second timeout using the k=10 nearest neighbors tests, I get
8 timeouts in the first 32 records using the old algorithm, and only 1
timeout using the new algorithm. The time for the very first test goes
from over a minute (I finally gave up) using the old algorithm to 0.08
seconds using the new one.

</p><p>

Obviously (in retrospect) the right solution is to pull out a couple
of those from my validation suite and turn them into test cases.

</p><p>

I never would have come up with these test cases before implementing
the new code - up until ten minutes ago I thought that the new code
only added a factor of two the code, not possible factors of 1,000!

</p>
<h2>Canonicalization: an in-depth analysis</h2>
<p>

I'm not finished with testing. I haven't fully characterized all the
parts of the implementation. For that matter, there are heuristics I
can still add. Here I'll describe what I did to analyze subgraph
SMARTS canonicalization. I conclude by finding that while it works, it
slows down the code and several days of development work ought to be
removed.

</p><p>

My MCS algorithm enumerates subgraph of one structure, converts that
into a SMARTS string, and tests if the pattern exists in other
structures.

</p><p>

There are many alternate ways to make a SMARTS string from a
subgraph. Given the linear chain of C O N, there's the reasonable CON
or NOC variations, the more confusing O(C)N and O(N)C, and crazy
variations like C1.N1O and O%987.N7.C%98. It's easy to make the
non-insane versions be generating a spanning tree. The question is
where to start the search and how to handle branches.

</p><p>

I believe that there are many duplicate patterns in a query. For
example, a benzene ring will generate many "ccc" queries. I can
minimize the number of substructure matches by caching earlier SMARTS
match results. But caching doesn't work if sometimes I get a CON and
sometimes I get a NOC. The solution is to generate a "canonical"
SMARTS for the subgraph - a unique representation for all of the
variations.

</p><p>

I implemented the CANGEN algorithm from
<a href="http://pubs.acs.org/doi/abs/10.1021/ci00062a008">SMILES. 2. Algorithm
for generation of unique SMILES notation</a> by Weininger, Weininger, and Weininger
J. Chem. Inf. Comput. Sci., 1989, 29 (2), pp 97-101 in order to choose
a canonical SMARTS. (But see 
<a href="http://organica1.org/seminario/cangen.pdf">Assigning Unique Keys to Chemical Compounds for Data Integration: Some Interesting Counter Examples</a>, Neglur, Grossman, and Liu, 2nd International Workshop on Data Integration in the Life Sciences (DILS 2005), La Jolla.)

</p><p>

Canonicalization is notoriously hard to get right. It too has a lot of
tricky corner cases. For example, in the late 1990s Daylight tracked
down a reported bug in their canonicalization implementation. They
algorithm requires a stable sort algorithm, but they used an unstable
sort. Their own internal testing never found the problem - it was a
customer who found the Solaris and IRIX boxes occasionaly returned
different values.

</p><p>

There could be similar bugs in my canonicalization algorithm. I don't
know. The usual solution is to generate large numbers of test cases,
randomize the order of the atoms and bonds, and verify that all of
them are the same. Here too it may be that only certain rare
topologies, or rare bond patterns, triggers an error. I'm not
convinced that I could come up with the right set of test cases for
it.

</p><p>

What makes it harder is that the underlying search algorithm doesn't
need a canonical SMARTS, so a canonicalization failure doesn't ever
show up in the output. I could have an infrequent bug and not notice
it!  Canonicalization is only there for performance reasons, but my
implementation is in Python, while the substructure matching is in
C++, so it might even be that the canonicalization time might be more
than the time saved.

</p><p>

I can make that a bit more nuanced. Canonical SMARTS generation has
three phases: 1) initial ranking, 2) canonicalization/tie-breaking,
and 3) SMARTS generation. I can disable the canonicalization step and
get a "semi-canonical" SMARTS (my initial ranking is more like a
circular fingerprint of diameter 3 than the atom characteristic from
Weininger et al.). I can also disable caching. Both of these are
doable with only a couple of changes to the code.

</p><p>

This leads to three cases: canonical SMARTS with caching,
semi-canonical SMARTS with caching, and semi-canonical SMARTS without
caching. (There should be a fourth step, which is arbitrary SMARTS,
but that requires more extensive changes.)

</p><p>

What I want to understand most is the effect of canonicalization on my
code. Again, I have to resort to aggregate timings and statistics
across a set of benchmarks. I used the ChEMBL-13 data set and
generated various benchmarks. One is based on computing the MCS
between 10,000 pairs selected at random, another contains the k=2,
k=10, and k=100 nearest neighbors of randomly chosen fingerprints
(timing 500 data sets each time), and the last is the total of 500
tests of the k&lt;=100 compounds with Tanimoto score of at least 0.95
to randomly selected fingerprints. My results (times are reproducible
to within a few percent) include the number of unique SMARTS
(canonical or non-canonical) generated and the total number of
substructure tests ("SS") which were carried out.

</p><p>
<table>

<tr><th colspan="2">Random pair timings</th><th># unique SMARTS</th><th># SS tests</th></tr>
<tr><th align="right">no cache</th><td>Total: 10000/467.3s (21.4/s) Complete: 9997/437.3s (22.9/s) Incomplete: 3/30.0s</td><td align="center">921666</td><td align="right">1339292</td></tr>
<tr><th align="right">semi-canonical</th><td>Total: 10000/421.3s (23.7/s) Complete: 9997/391.3s (25.6/s) Incomplete: 3/30.0s</td><td align="center">921666</td><td align="right">921666</td></tr>
<tr><th align="right">canonical</th><td>Total: 10000/442.1s (22.6/s) Complete: 9997/412.0s (24.3/s) Incomplete: 3/30.0s</td><td align="center">709636</td><td align="right">709636</td></tr>

<tr><th colspan="2">k=2 nearest neigbhors</th><th># unique SMARTS</th><th># SS tests</th></tr>
<tr><th align="right">no cache</th><td>Total: 500/287.3s (1.7/s) Complete: 484/127.1s (3.8/s) Incomplete: 16/160.2s</td><td align="center">264057</td><td align="right">320238</td></tr>
<tr><th align="right">semi-canonical</th><td>Total: 500/276.7s (1.8/s) Complete: 484/116.6s (4.2/s) Incomplete: 16/160.2s</td><td align="center">264057</td><td align="right">264057</td></tr>
<tr><th align="right">canonical</th><td>Total: 500/298.6s (1.7/s) Complete: 483/128.4s (3.8/s) Incomplete: 17/170.2s</td><td align="center">186682</td><td align="right">186682</td></tr>

<tr><th colspan="2">k=10 nearest neigbhors</th><th># unique SMARTS</th><th># SS tests</th></tr>
<tr><th align="right">no cache</th><td>Total: 500/520.5s (1.0/s) Complete: 471/230.0s (2.0/s) Incomplete: 29/290.5s</td><td align="center">447648</td><td align="right">3525563</td></tr>
<tr><th align="right">semi-canonical</th><td>Total: 500/490.1s (1.0/s) Complete: 472/209.5s (2.3/s) Incomplete: 28/280.6s</td><td align="center">447648</td><td align="right">2872040</td></tr>
<tr><th align="right">canonical</th><td>Total: 500/509.3s (1.0/s) Complete: 471/218.7s (2.2/s) Incomplete: 29/290.6s</td><td align="center">330010</td><td align="right">2109332</td></tr>

<tr><th colspan="2">k=100 nearest neigbhors</th><th># unique SMARTS</th><th># SS tests</th></tr>
<tr><th align="right">no cache</th><td>Total: 500/414.4s (1.2/s) Complete: 486/271.4s (1.8/s) Incomplete: 14/143.0s</td><td align="center">128781</td><td align="right">9932263</td></tr>
<tr><th align="right">semi-canonical</th><td>Total: 500/363.5s (1.4/s) Complete: 487/230.8s (2.1/s) Incomplete: 13/132.7s</td><td align="center">128781</td><td align="right">7456877</td></tr>
<tr><th align="right">canonical</th><td>Total: 500/361.8s (1.4/s) Complete: 488/239.5s (2.0/s) Incomplete: 12/122.4s</td><td align="center">107648</td><td align="right">6196764</td></tr>

<tr><th colspan="2">k&lt;=100 at or above Tanimoto threshold of 0.95</th><th># unique SMARTS</th><th># SS tests</th></tr>
<tr><th align="right">no cache</th><td>Total: 500/642.1s (0.8/s) Complete: 458/220.3s (2.1/s) Incomplete: 42/421.9s</td><td align="center">468661</td><td align="right">4388074</td></tr>
<tr><th align="right">semi-canonical</th><td>Total: 500/624.5s (0.8/s) Complete: 461/232.8s (2.0/s) Incomplete: 39/391.7s</td><td align="center">468661</td><td align="right">3828813</td></tr>
<tr><th align="right">canonical</th><td>Total: 500/640.9s (0.8/s) Complete: 460/239.2s (1.9/s) Incomplete: 40/401.8s</td><td align="center">364802</td><td align="right">3222366</td></tr>

</table>

</p><p>

Whew! That's a lot of data to throw at you. Please believe me when I
say that it took two days to generate correctly. BTW, "complete" means
that the MCS search algorithm went to completion, the "incomplete"
means that it timed out - here after 10 seconds - and gave a partial
solution.

</p><p>

What does this tell me? Obviously, caching is good. As expected, the
"semi-canonical" solution is always better than the "no cache" case,
and the canonicalization always reduces the number of substructures
and substructure tests. This means the canonicalization code is doing
<i>something</i> right.

</p><p>

Unfortunately, it seems like canonicalization has a big performance
impact. In the pairwise tests I do 922,000 canonicalizations in Python
to save 212,000 substructure tests, and I lose 21 seconds in doing
so. For the k=100 nearest neighbor benchmark, which is the only one
where the canonicalization code saves time, I do 129,000
canonicalizations to save 1,260,000 comparisons, and gain about 2
seconds. This suggests that each canonicalization takes as long as 10
substructure matches, and that RDKit can do 60,000 SMARTS matches per
second. A quick checks using one SMARTS gives 100,000 SMARTS matches
per second, which helps validate this estimate.

</p><p>

This means I should take out the canonicalization until it can be
implemented in C++. Granted, there may be a bug in the code, like
there was with an earlier hueristic. But there would have to be an
order of magnitude performance increase for this to be effective, and
I don't think that's likely.


</p>
<h2>Unit tests aren't enough to drive development</h2>
<p>

Which leads me back to my thesis. It would have been possible to
develop a few more unit tests for the canonicalization code. There
would have been some extra scaffolding in order to do that, but that's
a minor cost. I suspect that many of the tests would be very
implementation-dependent, and tied to specific internal function
calls. I don't like this because it means that a re-implementation of
this internal component in C++, which submerges many of the internal
helper functions and places them out of reach of Python-based unit
tests, would cause the unit tests to be un-runnable. And I am certain
that those unit tests would not be rigorous enough to be confident
that the code was working correctly.

</p><p>

Think about the question "should I write this code in Python or C++?".
It's a development-time question. Test Driven Development (TDD) is a
development methodology which uses unit tests to help make
development-time decisions. I think TDD is most helpful when
used to establish the minimum requirements for a project.

</p><p>

I don't see how TDD is helpful here. I can't think of any unit tests
which would guide this development decision. Sometimes you can write a
"spike solution" (also called a "prototype"):

<blockquote>

<a href="http://www.extremeprogramming.org/rules/spike.html">A spike
solution</a> is a very simple program to explore potential
solutions. Build the spike to only addresses the problem under
examination and ignore all other concerns.

</blockquote>

This sounds good, but what development style should you use to develop
the spike solution? Spikes are supposed to be throw-away code, but I
can't figure out how something other than a complete, tested
implementation of the canonical algorithm or the remaining growth
heuristics would have been useful. After all, a two line change in the
latter went from "working but 1% faster" to "working and 50% faster",
and I didn't even know if there was going to give a speedup in the
first place.

</p>
<h2>If not TDD, what methodology do I use?</h2>
<p>

Read Peter Seibel's <a href="http://gigamonkeys.wordpress.com/2009/10/05/coders-unit-testing/">Unit
testing in Coders at Work</a>. The author interviewed various famous
programmers and learned more about how they tested their software. You
may also want to read the related <a href="http://news.ycombinator.com/item?id=863219">comments on Hacker
News</a>.


</p><p>

Seibel recounts that Joshua Bloch "wrote a monstrous 'basher'" which
found "that occasionally, just occasionally, the basher would fail its
consistency check." Bloch then wrote tests to pin down the failure,
eventually finding the fault in a system mutex. Note that under normal
unit test development you assume that your underlying components are
correct, so this isn't something you would normally code for.

</p><p>

Seibel also reports that others assemble a large amount of test cases
and uses that to check their code. This is of course the technique I
used for the MCS problem.

</p><p>

It feels as trite as saying that the secret to losing weight is diet
and exercise, but my method for programming is to understand the
problem, implement it, and test it until you are confident that it's
good enough. That knowledge of how to do that comes from <a href="http://www.dalkescientific.com/writings/diary/archive/2007/08/17/kata_and_practice.html">experience,
practice, reflection, and discussion</a>.

</p><p>

For those who scoff and call this "big design up front," I merely
point you to earlier parts of this essay. When I started this code I
had a rough idea that it would work. I had previously implemented <a href="http://www.dalkescientific.com/writings/diary/archive/2011/01/10/subgraph_enumeration.html">substructure
enumeration</a>, and the Weininger et al. canonicalization algorithm
and SMARTS generation, so I knew that the components were possible,
but I didn't know how they went together. Instead, I let the code
development itself guide me. I thought some, I implemented code, I
"ran the code in my head", I reflected on what the tricky parts were,
I thought about how to make them more clear, and I tried various
was to improve the code.

</p><p>

That was a lot to keep in my head, I wasn't sure if the result would
be fast enough, and I had no way good way to test its usefulness until
most of the code was in place. No wonder it was mentally taxing!

</p><p>

I believe tests - including unit tests implemented during development
- are important. I don't believe that unit tests are good enough to
guide complex algorithm development. However, most programming (over
95%?) is not complex algorithm development; complicated? yes, but not
complex.

</p><p>

I once jokingly said that TDD is not useful if there's two or more
embedded for loops. That's a bit of a simplification, but not far from
my feelings. Some classes of problems, like complex algorithm
development and security analysis, require a different attitude
towards programming, emphasizing "what can go wrong?" and "how can I
improve my confidence that the code is working correctly?" It's my
view that this doubt-based philosophical attitude is missing from most
discussions of software development practices.

</p><p>

And perhaps as fundamental, when I have to be that critical of my own
work and probe it for failures and be open to the possibility of nasty
gotchas lurking in the deep dark corners, then some of that doubt
passes over into my personal life. I empathize with the idea of not
living in that "strange place" all the time, and I can see why this
isn't a common attitude.

</p>
<h2>Comments</h2>
<p>

This essay is meant to be a thoughtful reflection on the difficulties
of programming, using the MCS problem to provide specific
structure. If you want to <a href="http://dalkescientific.blogspot.com/2012/05/maximum-common-substructures-and-fmcs.html">leave
comments about the MCS portion</a> then use the MCS comment site.
Otherwise, <a href="http://dalkescientific.blogspot.se/2012/05/testing-hard-algorithms.html">leave
a comment on testing hard algorithms</a>.

</p>]]></description>
    <link><![CDATA[http://www.dalkescientific.com/writings/diary/archive/2012/05/21/testing_hard_algorithms.html]]></link>
    <pubDate>2012-05-21 12:00:00</pubDate>
  </item>
  <item>
    <title><![CDATA[Daniel Greenfeld: May 12th, 2012 LA Open Source Recap]]></title>
    <description><![CDATA[<p>On May 12th, 2012, over 50 <a class="reference external" href="http://python.org">Python</a>, <a class="reference external" href="http://en.wikipedia.org/wiki/C%2B%2B">C++</a>, <a class="reference external" href="http://www.ruby-lang.org/">Ruby</a>, <a class="reference external" href="http://www.php.net/">PHP</a>, <a class="reference external" href="http://en.wikipedia.org/wiki/JavaScript">JavaScript</a>, and <a class="reference external" href="http://nodejs.org/">Node.js</a> developers arrived to code on a variety of projects. It was awesome! Tons of open source projects saw contributions, and people across languages and frameworks worked together.</p>
<a class="reference external image-reference" href="http://www.flickr.com/photos/59834630@N07/7193954598/"><img alt="http://farm9.staticflickr.com/8007/7193954598_1b071cb5e4.jpg" class="align-center" id="may-12-open-source-sprint" src="http://farm9.staticflickr.com/8007/7193954598_1b071cb5e4.jpg" /></a>
<div class="section" id="event-background">
<h2>Event Background</h2>
<p>Less then two weeks before May 12, a bunch of us Los Angeles area Python developers were hanging out and wishing we had a local sprint to attend that was just about developers working on open source projects. It was then that <a class="reference external" href="http://audreymroy.com">Audrey Roy</a> and I, along with an army of hardworking volunteers, decided to stop wishing and make it happen on May 12th.</p>
<p>We lined up a venue, contacted awesome sponsors <a class="reference external" href="http://spire.io">Spire.io</a>, <a class="reference external" href="http://heroku.com">Heroku</a>, <a class="reference external" href="https://github.com">Github</a>, <a class="reference external" href="http://cars.com">Cars.com</a>, and <a class="reference external" href="https://academy.cartwheelweb.com">Cartwheel Academy</a>. As we did that, we also invited people from the many Los Angeles programming communities in Los Angeles to join us. The result of everyone's hard work? <strong>We filled up all sixty spots in less than 96 hours!</strong></p>
<p>Some of the projects worked on included:</p>
<ul class="simple">
<li>Salt Stack: <a class="reference external" href="https://github.com/saltstack/salt">https://github.com/saltstack/salt</a></li>
<li>A node.js-powered streaming terminal, allowing for shared input at a terminal among several participants.</li>
<li>A JavaScript powered astrolabe.</li>
<li>Settlers of Catan analytics in JavaScript.</li>
<li><a class="reference external" href="http://www.openframeworks.cc/">OpenFrameworks</a>, a cross-platform toolkit for creative coding in C++.</li>
<li>My own time at the sprint was spent with Audrey Roy and <a class="reference external" href="http://rdegges.com">Randall Degges</a> on engineering cleanup and fixing bugs on <a class="reference external" href="https://github.com/opencomparison/opencomparison">OpenComparison</a>.</li>
</ul>
</div>
<div class="section" id="more-open-source-sprinting-on-july-15">
<h2>More open source sprinting on July 15</h2>
<p>There's going to be another Los Angeles open source event on July 15 at <a class="reference external" href="http://originate.com/">Originate</a>. Instead of less then two weeks to plan, we have nearly two months - so it's going to be better!</p>
<p>RSVP here: <a class="reference external" href="http://www.meetup.com/LA-Hackathons/events/64542582/">http://www.meetup.com/LA-Hackathons/events/64542582/</a></p>
<p>If you want to sponsor or volunteer, email me at pydanny (at) cartwheelweb.com or audreyr (at) cartwheelweb.com. We go out of our way to ensure that sponsors and volunteers feel appreciated.</p>
<a class="reference external image-reference" href="http://www.flickr.com/photos/59834630@N07/7193961164/"><img alt="http://farm9.staticflickr.com/8003/7193961164_b26d27093d.jpg" class="align-center" id="me-and-audrey-at-the-open-source-sprint" src="http://farm9.staticflickr.com/8003/7193961164_b26d27093d.jpg" /></a>
</div>]]></description>
    <link><![CDATA[http://pydanny.com/may-12th-2012-la-open-source-recap.html]]></link>
    <pubDate>2012-05-21 09:30:00</pubDate>
  </item>
  <item>
    <title><![CDATA[PyLadies: SF PyLadies First Workshop: Build your own Blog]]></title>
    <description><![CDATA[SF PyLadies First Workshop: Build your own Blog]]></description>
    <link><![CDATA[http://pyladies.com/blog/sf-pyladies-first-workshop-build-your-own-blog/]]></link>
    <pubDate>2012-05-21 08:37:08</pubDate>
  </item>
  <item>
    <title><![CDATA[Zaki Akhmad: Python Indonesia Meetup #4]]></title>
    <description><![CDATA[Yes, we&#8217;re back with meetup. This is the fourth meetup. Well, actually it&#8217;s my first Python Indonesia meetup. The meetup was held at detik.com office. The official meetup announcement was published by Fanani here. I came a little bit late &#8230; <a href="http://zakiakhmad.wordpress.com/2012/05/21/python-indonesia-meetup/">Lanjut membaca <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=zakiakhmad.wordpress.com&blog=100750&post=1781&subd=zakiakhmad&ref=&feed=1" width="1" height="1" />]]></description>
    <link />
    <pubDate>2012-05-21 06:30:00</pubDate>
  </item>
  <item>
    <title><![CDATA[Ruslan Spivak: Logsna &#8211; a sane log output format]]></title>
    <description><![CDATA[<p></p><p>Good old log files are still the most reliable, versatile, and useful sources of information.<br />
When they are also human-readable and easy to use with standard Unix tools like <strong><em>tail</em></strong> and <strong><em>grep</em></strong> they are even more useful.</p>
<p>We all know that especially in time of stress when things with a system are going south having a quick and easy way to grep for useful information is critical. The purpose of a small Python utility <a href="https://github.com/rspivak/logsna">Logsna</a> is to provide a sane log output format that makes some grepping a bit easier.</p>
<p><a href="https://github.com/rspivak/logsna">Logsna</a> offers a custom formatter class <em>logsna.Formatter</em> that can be used in a logging config file, for example:</p>
<pre class="brush: python; title: ; notranslate">
# sanefmt.py
import logging
import logging.config
from StringIO import StringIO

CONFIG = &quot;&quot;&quot;\
[loggers]
keys=root

[handlers]
keys=console

[handler_console]
class=logging.StreamHandler
args=(sys.stderr,)
formatter=sane

[formatters]
keys=sane

[logger_root]
level=DEBUG
handlers=console

# Our custom formatter class
[formatter_sane]
class=logsna.Formatter
&quot;&quot;&quot;

config = StringIO(CONFIG)
logging.config.fileConfig(config)

log = logging.getLogger('mylogger.component1')

log.debug('debug message')
log.info('info message')
log.warning('warning message')
log.critical('critical message')
try:
    1 / 0
except:
    log.exception('Houston we have a problem')
</pre>
<h4>The Log Format</h4>
<p>Here is an output from the above program:</p>
<pre class="brush: bash; title: ; notranslate">
DEBUG    [2012-05-21 01:59:23,686] mylogger.component1: debug message
INFO     [2012-05-21 01:59:23,686] mylogger.component1: info message
WARNING  [2012-05-21 01:59:23,686] mylogger.component1: warning message
CRITICAL [2012-05-21 01:59:23,686] mylogger.component1: critical message
ERROR    [2012-05-21 01:59:23,686] mylogger.component1: Houston we have a problem
! Traceback (most recent call last):
!   File &quot;/home/alienoid/python/sanefmt.py&quot;, line 67, in
!     1 / 0
! ZeroDivisionError: integer division or modulo by zero
</pre>
<h4>The Log Format Notes</h4>
<p>- All timestamps are in <strong>ISO8601</strong> and <strong>UTC</strong> format</p>
<p>- To grep for messages of a specific level</p>
<pre class="brush: python; title: ; notranslate">
$ tail -f sanefmt.log | grep '^INFO'
</pre>
<p>- To grep for messages from a particular logger</p>
<pre class="brush: bash; title: ; notranslate">
$ tail -f sanefmt.log | grep 'component1:'
</pre>
<p>- To pull out full exception tracebacks with a corresponding log message</p>
<pre class="brush: bash; title: ; notranslate">
$ tail -f sanefmt.log | grep -B 1 '^\!'
</pre>
<h4>Installation</h4>
<pre class="brush: bash; title: ; notranslate">
$ [sudo] pip install logsna
</pre>]]></description>
    <link><![CDATA[http://ruslanspivak.com/2012/05/20/logsna-a-sane-log-output-format/]]></link>
    <pubDate>2012-05-21 04:03:04</pubDate>
  </item>
  <item>
    <title><![CDATA[The Blagin' Wraith: An Exciting Update]]></title>
    <description><![CDATA[Sometimes when you are waiting for something, time goes by very slowly. But because you are so focused on that one thing, everything else in life moves really fast. I've been unemployed since the end of January. During that time I made <a href="https://github.com/wraithan/zenircbot">ZenIRCBot</a> significantly better, I wrote a simple site for tracking <a href="http://training.wraithan.net/">your workout stats</a>, I attended two conferences, PyCon and Barcamp Portland. I visited two states that I'd never been to. Flew for the first time and took my longest train ride.<br /><br />Basically I've done a ton in this time. But it feels like it has been a really long time because I've been so focused on getting my resume put together with <a href="http://mozilla.org/">Mozilla </a>in mind. Then once I finally had that to a point that I was happy, I started showing it to friends for them to review and that took forever. Then I handed it off to my friend Jason to apply and write a letter of recommendation for me.<br /><br />Then I waited another eternity (it felt like at least) to hear back, be flown down and get an offer from them. I was so focused on that, that everything else flew by me and I may not have gotten the most out of things. Which is fine because I'll be starting at Mozilla on the 29th of May. Working on <a href="http://addons.mozilla.org/">http://addons.mozilla.org</a> and related sites with the WebDev team.<br /><br />What that should really read as, is that I am incredibly lucky to be getting the chance to work at a company that I'd only really dreamt of working at before. I'm going to be working with some awesomely brilliant people, for a company who's <a href="http://www.mozilla.org/about/mission.html">mission</a> is to make the web a better place, while working on some really interesting and difficult engineering, doing it in a language I love (Python) with a framework I love (Django). If you know me, then you know how much I love working on interesting hard problems.<br /><br />I'm writing this mostly as a stream of consciousness because I don't have a better way to put this stuff together. In the future I'm hoping to take some time, get some peer review for my posts before I put them up and talk about the awesome things I'm doing at Mozilla and in my free time. If you want to be someone to helps me with my writing, let me know, I could use all the help I can get.<br /><br />-Wraithan<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/3548273165051172931-7604208144512419161?l=blog.wraithan.net" alt="" /></div>]]></description>
    <link><![CDATA[http://blog.wraithan.net/2012/05/exciting-update.html]]></link>
    <pubDate>2012-05-21 02:02:34</pubDate>
  </item>
  <item>
    <title><![CDATA[Baiju Muthukadan: BangPypers meetup (Yesterday)]]></title>
    <description><![CDATA[<span>Yesterday we had BangPypers meeting at ZeOmega office. There was 10 members came for the meeting. There was no specific agenda for the meeting, we discussed some general topics related to Python.<br /><br />I demonstrated the installation of Salt in Windows XP ( <a href="http://saltstack.org/">http://saltstack.org/</a> ). Salt is a remote execution and configuration management tool. For those who missed, here is the screencast I created today for the installation of Salt in Windows: <a href="http://www.youtube.com/watch?v=eeJByb-alz8">http://www.youtube.com/watch?v=eeJByb-alz8</a> BTW, community is working on a unified installer for Windows.<br /><br />If you are interested to learn more about Salt, look at the excellent documentation here:</span><br /><span><a href="http://salt.readthedocs.org/en/latest/index.html">http://salt.readthedocs.org/en/latest/index.html</a><br /><br />You can replace remote execution systems like Fabric &amp; Capistrano with Salt. Also you can replace configuration management systems like Puppet, Chef &amp; CFEngine.<br /><br />I have tried Salt with RHEL,CentOS,Debian,Ubuntu,Fedora,FreeBSD,Windows 2008 Server R2 and Windows XP. For example, if you want to install Salt in a CentOS machine, just run these two commands:<br /><br /> rpm -Uvh <a href="http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-6.noarch.rpm">http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-6.noarch.rpm</a><br /> yum install salt*<br /><br />Similarly for Ubuntu:<br /><br />add-apt-repository ppa:saltstack/salt<br />apt-get update<br />apt-get install salt-master salt-minion<br /><br />While talking about Salt, I also happened to demonstrate Jenkins server I setup for the same project ( <a href="http://jenkins.saltstack.org/">http://jenkins.saltstack.org/</a> ). Here is the screencast I created sometimes back for the same project: <a href="http://www.youtube.com/watch?v=7IRzPFYtyD4">http://www.youtube.com/watch?v=7IRzPFYtyD4</a> This screencast walk through various code metrics available for Python like: clonedigger, pep8, pyflakes, pylint &amp; sloccount.</span><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/5718509407322520047-2298805946971240316?l=baijum.blogspot.com" alt="" /></div>]]></description>
    <link><![CDATA[http://baijum.blogspot.com/2012/05/bangpypers-meetup-yesterday.html]]></link>
    <pubDate>2012-05-20 23:43:32</pubDate>
  </item>
  <item>
    <title><![CDATA[Lightning Fast Shop: Release 0.7.4]]></title>
    <description><![CDATA[<p>We just released&nbsp;<a href="http://pypi.python.org/pypi/django-lfs/0.7.4" target="_blank">LFS 0.7.4</a>.&nbsp;This is a yet another bugfix release of the 0.7 branch.</p>
<div>
<h2>Changes</h2>
<ul class="simple">
<li>Improved shipping and payment method management: display form errors; using ajax; issue #151.</li>
<li>Bugfix: send order_paid signal after successful callback arrived from PayPal; issue #198.</li>
<li>Bugfix: make PayPal callbacks work with csrf protection; issue #197.</li>
<li>Bugfix: catch wrong floats in calculate_packing.</li>
<li>Bugfix: fixed update cart after login for configurable products; #issue gh #8</li>
<li>Bugfix: cleaned up parameters and arguments of PriceCalculator.</li>
<li>Bugfix: don't pass request to PriceCalculator base_packing_price methods.</li>
<li>Bugfix: fixed calculation of package prices for configurable products.</li>
<li>Bugfix: Fixed wrong arguments in calls to voucher API. (Pavel Zagrebelin)</li>
</ul>
<div>
<h2>Information</h2>
<p>You can find more information and help on following locations:</p>
<ul>
<li><a href="http://packages.python.org/django-lfs/index.html" target="_blank">Documentation on PyPI</a></li>
<li><a href="http://demo.getlfs.com" target="_blank">Demo</a></li>
<li><a href="http://pypi.python.org/pypi/django-lfs" target="_blank">Releases on PyPI</a></li>
<li><a href="http://bitbucket.org/diefenbach/django-lfs" target="_blank">Source code on bitbucket.org</a>&nbsp;and&nbsp;<a href="https://github.com/diefenbach/django-lfs" target="_blank">github</a>.</li>
<li><a href="http://groups.google.com/group/django-lfs" target="_blank">Google Group</a></li>
<li><a href="http://twitter.com/lfsproject" target="_blank">lfsproject on Twitter</a></li>
<li><a href="irc://irc.freenode.net/django-lfs" target="_blank">IRC</a></li>
</ul>
</div>
<h2>LFS moved to github</h2>
<p><a href="http://www.getlfs.com/manage/lfs-has-been-moved-github">See here for more</a>.</p>
<h2>LFS on EuroPython 2012</h2>
<p>We are sprinting on this year's&nbsp;<a href="https://ep2012.europython.eu/" target="_blank">EuroPython in Florence</a>. Don't hesitate to join us, see&nbsp;<a href="https://ep2012.europython.eu/p3/sprints/" target="_blank">https://ep2012.europython.eu/p3/sprints/</a>&nbsp;and&nbsp;<a href="https://docs.google.com/a/iqpp.de/document/d/1eW6NWpvtUPq9c3Sny-R4xb_D1h0wXaj2ZHXqQGvtpZU/edit" target="_blank">LFS sprint topics</a>&nbsp;for more.</p>
</div>
<p>&nbsp;</p>]]></description>
    <link><![CDATA[http://www.getlfs.com/release-074]]></link>
    <pubDate>2012-05-20 17:44:45</pubDate>
  </item>
  <item>
    <title><![CDATA[Lightning Fast Shop: Release 0.6.17]]></title>
    <description><![CDATA[<p>
<p>We just released&nbsp;<a href="http://pypi.python.org/pypi/django-lfs/0.6.17" target="_blank">LFS 0.6.17</a>.&nbsp;This is a yet another bugfix release of the 0.6 branch.</p>
<div>
<h2>Changes</h2>
<p>
<div id="id1" class="section">
<ul class="simple">
<li>Bugfix: fixed update cart after login for configurable products; #issue gh #8</li>
<li>Bugfix: make PayPal callbacks work with CSRF protection; issue #197 (Dmitry Chaplinsky)</li>
<li>Bugfix: Fixed wrong arguments in calls to voucher API (Pavel Zagrebelin)</li>
<li>Bugfix: catch wrong floats in calculate_packing</li>
</ul>
</div>
</p>
<div>
<h2>Information</h2>
<p>You can find more information and help on following locations:</p>
<ul>
<li><a href="http://packages.python.org/django-lfs/index.html" target="_blank">Documentation on PyPI</a></li>
<li><a href="http://demo.getlfs.com" target="_blank">Demo</a></li>
<li><a href="http://pypi.python.org/pypi/django-lfs" target="_blank">Releases on PyPI</a></li>
<li><a href="http://bitbucket.org/diefenbach/django-lfs" target="_blank">Source code on bitbucket.org</a>&nbsp;and&nbsp;<a href="https://github.com/diefenbach/django-lfs" target="_blank">github</a>.</li>
<li><a href="http://groups.google.com/group/django-lfs" target="_blank">Google Group</a></li>
<li><a href="http://twitter.com/lfsproject" target="_blank">lfsproject on Twitter</a></li>
<li><a href="irc://irc.freenode.net/django-lfs" target="_blank">IRC</a></li>
</ul>
</div>
<h2>LFS moved to github</h2>
<p><a href="http://www.getlfs.com/manage/lfs-has-been-moved-github">See here for more</a>.</p>
<h2>LFS on EuroPython 2012</h2>
<p>We are sprinting on this year's&nbsp;<a href="https://ep2012.europython.eu/" target="_blank">EuroPython in Florence</a>. Don't hesitate to join us, see&nbsp;<a href="https://ep2012.europython.eu/p3/sprints/" target="_blank">https://ep2012.europython.eu/p3/sprints/</a>&nbsp;and&nbsp;<a href="https://docs.google.com/a/iqpp.de/document/d/1eW6NWpvtUPq9c3Sny-R4xb_D1h0wXaj2ZHXqQGvtpZU/edit" target="_blank">LFS sprint topics</a>&nbsp;for more.</p>
</div>
<div></div>
</p>]]></description>
    <link><![CDATA[http://www.getlfs.com/release-0617]]></link>
    <pubDate>2012-05-20 17:44:45</pubDate>
  </item>
  <item>
    <title><![CDATA[Kay Schluehr: Greedy grammars and Any]]></title>
    <description><![CDATA[<h3>. in your regular expression</h3>

<p>I only vaguely remember my first encounter with a parser generator which must by dated back to the late 1990s. I guess it was <a href="http://pages.cpsc.ucalgary.ca/~aycock/spark/">Spark</a> by John Aycock, an Early parser. What puzzled me back then was the need to be explicit down to the character level.  Regular expression engines, albeit cryptic, were a revelation because one could specify the structural information one needed and match the rest using a &#8216;.&#8217; which is the wildcard pattern that matches <em>any</em> character<em>.</em></p>

<p>I came back to <em>Any</em> in the Trail parser generator lately. I was motivated by writing a reversible C preprocessor. Unlike conventional C preprocessors which are used in the compilation chain of C code, a reversible C preprocessor can used to refactor C code, while retaining the preprocessor directives and the macro calls. This is basically done by storing the #define directive along with the code to be substituted and the substitution. The substituted code and the substitution are exchanged after the refactoring step, such that it looks like no substitution happened at all.</p>

<p>A comprehensive C preprocessor grammar can be found on the <a href="http://msdn.microsoft.com/en-us/library/2scxys89%28v=vs.80%29.aspx">following</a> MSDN site. What is most interesting to us are the following two EBNF productions:</p>

<blockquote><em>#</em> <strong>define </strong> <em>identifier</em>[<strong>(</strong> <em>identifier</em><sub>opt</sub><strong>, </strong><em>...</em> <strong>,</strong> <em>identifier</em><sub>opt</sub> <strong>)</strong>] <em>token-string</em><sub>opt</sub>

<dl> <dt> <em>token-string </em>: </dt> <dd>String of tokens&nbsp;

</dd> </dl></blockquote>

<p>The <em>String of tokens</em> phrase this is <em>Any+</em>.</p>

<h3>Bon appetite</h3>

<p>Suppose one defines two macros</p>

<p><span>#define</span> <span>min(a,b) ((a)</span>&lt;<span>(b)?(a):(b))</span></p>

<p><span>#define</span> <span>max(a,b) ((a)</span>&lt;<span>(b)?(b):(a))</span></p>

<p>Obviously the defining string of the <span>min</span> macro can be recognized using <em>token-string</em> but how can we prevent that <em>token-string</em> eats the <span>max</span> macro as well? Once in motion token-string has a sound appetite and will eat the rest. The solution to this problem in case of regular expressions is to make <em>Any</em> non-greedy. The non-greediness can easily be expressed using the following requirement:</p>

<p>If <span>S | Any</span> is a pattern with <span>S!=Any</span>. If S can match a character, <span>S</span> will be preferred over <span>Any</span>.</p>

<p>In the production rule
<pre>R: ... Any* S ...</pre>
we can be sure that if S matches in R then Any won&#8217;t be used to match &#8211; although it would match if we leave it greedy. Same goes with
<pre>R: ... (Any* | S) ...</pre></p>

<h3>Non greediness in grammars</h3>

<p>Grammars are more complicated than regular expressions and we have to take more care about our greediness rules. To illustrate some of the problems we take a look on an example
<pre>R: A B | C
A: a Any*
B: b
C: c</pre>
<span>Any</span> causes a follow/first conflict between A and B. Making <span>Any</span> non-greedy alone won&#8217;t help because a grammar rule or its corresponding NFA is always greedy! It follows a longest match policy and an NFA will be traversed as long as possible. So once the NFA of A is entered it won&#8217;t be left because of the trailing <span>Any*</span>.</p>

<p>Detecting the trailing <span>Any</span> in A is easy though. We solve the follow/first conflict with a trailing <span>Any</span> by embedding <span>A</span> into <span>R</span>. Embedding strategies are the centerpiece of Trail and they shall not be recapitulated here. Just so much: embedding A in R doesn&#8217;t destroy any information relevant for parsing. If A has been embedded <span>Any*</span> will be delimited by <span>B</span> to the right and we can safely apply R without the danger of <span>Any</span> consuming a token &#8216;b&#8217;.</p>

<p>Eventually we have to re-apply our embedding strategy: if <span>A</span> is a rule with a trailing <span>Any</span> and <span>A</span> is embedded in <span>B</span> and <span>B</span> has a trailing <span>Any</span> <em>after</em> this embedding  then <span>B</span> will be embedded wherever possible.</p>

<h3>A short experiment</h3>

<p>Here is a mini-Python grammar is used to detect Python class definitions.
<pre>file_input: (NEWLINE | stmt)* ENDMARKER
classdef: 'class' NAME ['(' <span><strong>Any</strong></span>+ ')'] ':' suite
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
simple_stmt: <span><strong>Any</strong></span>* NEWLINE
stmt: simple_stmt | compound_stmt
compound_stmt: classdef | <span><strong>Any</strong></span>* suite</pre>
<em> </em></p>

<p>Unlike a real Python grammar it is fairly easy to build. All rules are taken from the Python 2.7 grammar but only <span>file_input</span>, <span>suite</span> and <span>stmt</span> remained unchanged. In all other cases we have replaced terminal/non-terminal information that isn&#8217;t needed by <span>Any</span>.</p>

<p>&nbsp;</p>

<p><em>
</em></p>

<p>&nbsp;</p>]]></description>
    <link><![CDATA[http://fiber-space.de/wordpress/2012/05/20/greedy-grammars-and-any/]]></link>
    <pubDate>2012-05-20 16:01:39</pubDate>
  </item>
  <item>
    <title><![CDATA[Doug Hellmann: virtualenvwrapper 3.4]]></title>
    <description><![CDATA[<br /><div class="document" id="virtualenvwrapper-3-4"><div class="section" id="what-is-virtualenvwrapper"><h4>What is virtualenvwrapper</h4><p><a class="reference external" href="http://www.doughellmann.com/projects/virtualenvwrapper/">virtualenvwrapper</a> is a set of extensions to Ian Bicking's <a class="reference external" href="http://pypi.python.org/pypi/virtualenv">virtualenv</a><br />tool.  The extensions include wrappers for creating and deleting<br />virtual environments and otherwise managing your development workflow,<br />making it easier to work on more than one project at a time without<br />introducing conflicts in their dependencies.</p></div><div class="section" id="what-s-new"><h4>What's New</h4><ul class="simple"><li>Add a "lazy loading" option for startup scripts. Refer to the<br /><a class="reference external" href="http://www.doughellmann.com/docs/virtualenvwrapper/install.html#lazy-loading">installation instructions</a><br />for more details.</li></ul></div><div class="section" id="installing"><h4>Installing</h4><p>Visit the <a class="reference external" href="http://www.doughellmann.com/projects/virtualenvwrapper/">virtualenvwrapper</a> project page for download links and<br />installation instructions.</p></div></div><br /><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/5440028356946346379-4119833878495362331?l=blog.doughellmann.com" alt="" /></div>]]></description>
    <link><![CDATA[http://blog.doughellmann.com/2012/05/virtualenvwrapper-34.html]]></link>
    <pubDate>2012-05-20 11:27:02</pubDate>
  </item>
  <item>
    <title><![CDATA[Hynek Schlawack: My Road to the Python Commit Bit]]></title>
    <description><![CDATA[<p>Like many <a href="http://en.wikipedia.org/wiki/FOSS">FOSS</a> fans, I always wanted to be an active part of the movement. My last <a href="http://simplemail.sourceforge.net/">big project</a> was for the <a href="http://en.wikipedia.org/wiki/Amiga">Amiga</a> in the past millennium though. Nowadays I’m happy that after years of small-scale dabbling on various projects I’ve found my haven. I’d like to share my way to my recent gain of push privileges on the <a href="http://www.python.org/">Python</a> project and hope to inspire some of you to do the same.</p>
<h3>The Problem</h3>
<p>It <a href="http://brandonhays.com/blog/2011/05/03/why-i-still-dont-contribute-to-open-source/">isn’t easy</a> to start contributing to FOSS. <a href="https://github.com/torvalds/linux/pull/17#issuecomment-5659970">Some projects</a> seem even not to be particularly interested in new contributors – because everyone wants to contribute for fame and glory. <a href="http://twistedmatrix.com/pipermail/twisted-python/2011-July/024193.html">Others</a> could use help but aren’t eager to get new patches because of ample amounts of code rotting in the bug tracker. But there are plenty of <a href="https://twitter.com/#!/zzzeek/status/203248503579869185">projects</a> that <em>want</em> you to help.</p>

<p>And yes, even <a href="http://www.python.org/">CPython</a> — i.e. the most widespread Python implementation as of 2012, I’ll call it just “Python” henceforth — needs your help! That’s the reason it’s active in <a href="http://pythonmentors.com/">its outreach</a> to new contributors. Please note I said “contributors”, you don’t have to be a programmer – or do programmer’s work – to help.</p>

<p>Python core development has always been a welcoming place. But <a href="https://twitter.com/#!/jessenoller">Jesse</a> tried to push things even <a href="http://jessenoller.com/2011/05/05/on-contribution/">farther</a>. And he succeeded at that – it’s easily one of the best places to hang out with people way smarter than you (or at least me) without being patronized.</p>

<p>But it’s hard to get started with new code and often even harder to get started with a new community. So what’s the most important personal attribute to get into a high profile open source project like Python, Django or Twisted? Hint: it’s like with everything important in life you can’t buy.</p>
<h3>The Solution</h3>
<p><strong>Perseverance.</strong></p>

<p>People sense that but don’t believe it. It’s just like kids don’t believe they’ll ever become adults and their parents were where they are now at some point in prehistoric times. And just like that, the now famous CPython developers once started submitting patches to a tracker and prayed for someone to notice.</p>

<p>I’m in no way famous but I think that’s exactly what it makes easier for you to relate to me.</p>

<p>Please compare the dates between my <a href="http://bugs.python.org/issue12709">first patch</a> (2011-08-08) to the bug tracker and the day I got my <a href="http://docs.python.org/devguide/developers.html">push rights</a> (2012-05-14): <em>nine months</em>. What’s even worse, my <a href="http://bugs.python.org/issue12708">first real code patch</a> rotted for <em>four months</em> in the tracker. I’ll be honest with you: I walked away from Python core development at this point.</p>

<blockquote>
<p>“If they don’t want my help, I’ll look elsewhere.”</p>
</blockquote>

<p>Fortunately, Antoine gave me my “christmas presents” and committed it at last out of nowhere. That made me come back and I’m really happy about that. But was it really necessary for me to leave my ambitions? Not really. I’ll try to draw a picture of the real situation.</p>

<p>The problem is: the delay didn’t indicate that Python isn’t interested in my help. It proved it <em>needs</em> my help very much.</p>

<p>Although there are <a href="http://www.python.org/dev/committers">lots of committers</a>, only few of them are active (try running <code>hg churn -c -d '2012 to 2013'</code> if you don’t believe me). Committing code to a project like Python is different than dabbling on some small project. We have a high responsibility to not break stuff livelihoods depend on. Someone who commits your code has to fully understand what it’s doing and takes responsibility for your patch (although breaking stuff isn’t really a crime as long as it breaks loudly, that’s what we have <a href="http://www.python.org/dev/buildbot/">buildbots</a> for).</p>

<p>So, logically few active committers means few checkins means long delays on patches.</p>

<p>So in the beginning, you <em>really</em> need some patience. It also helps to hang out and socialize on <a href="http://freenode.net/">Freenode</a>’s #python-dev or the Python <a href="http://mail.python.org/mailman/listinfo">mailing lists</a> (although I’m rather shy on posting on mailing lists myself; it doesn’t feel good to ask basic stuff that gets archived forever). Your also gain good karma but reviewing code of others and generally being active on the <a href="http://bugs.python.org/">bug tracker</a>. Once some of your patches have been committed, other developers will be much more open to look at your code. We’re all human in the end and you would also rather help out a friend, no?</p>

<p>And that would have been the better way for instead of retiring. While I was on IRC, I wasn’t really active on the tracker building up reputation. After my first patches were committed and I started triaging and reviewing, people even started asking me whether I need to have something reviewed.</p>

<p>When you arrive at this point, you’re over the hump. Contributing becomes much less of a insular patience game and much more of a social experience. You’re part of a community hacking on something cool – and while there’ll always be friction where people gather and you’ll still have to wait for reviews – it’s a lot of fun.</p>

<p>And one day – out of the blue – you’ll get extended privileges offered. At this point it’s important to keep your cool; too many people started doing way too much, burning out and stopping doing anything at all.</p>
<h3>What Python Needs Most</h3>
<p>We need <a href="http://docs.python.org/devguide/tracker.html#helptriage">triagers</a> that weed through tickets – <a href="http://mail.python.org/mailman/listinfo/new-bugs-announce">new</a> and old – and help to close them. Be it by reviewing code, checking spelling, grammar and wording, trying to reproduce the problems – we’re especially in need of capable Windows users – or just pinging stale tickets and adding suitable developers to the watch lists. There’s a lot to do and the current team is glad to be able keep up with new stuff, but there are 1,500 and growing tickets with patches open – and I’d like very much to change that.</p>

<p>Let me stress at this point that it’s unlikely that you get commit rights if you just add own patches and wait for them to be committed. It’s expected from you to take part at the whole development process.</p>

<p>So my foremost priority for the next months is doing exactly that: cut back on own coding and weed through tickets and make people happy by getting simple stuff merged or at least noticed. I know from personal experience that ignored patches are worse than rejected ones.</p>

<p>But I could use the help of people like <em>you</em>, who speak Python or English and are willing to learn Python’s <a href="http://docs.python.org/devguide/">development process</a>! Get an account on the tracker, familiarize yourself with our <a href="http://docs.python.org/devguide/tracker.html#helptriage">triaging process</a> and start triaging! Meanwhile, feel free to ask your questions on <a href="http://freenode.net/">Freenode</a>’s #python-dev or our <a href="http://mail.python.org/mailman/listinfo/core-mentorship">core-mentorship</a> mailing list.</p>

<p>Your efforts will be noticed. And nothing’s as fun as <a href="http://d.pr/i/EqHC">breaking</a> all <a href="http://www.python.org/dev/buildbot/">buildbots</a> with one commit. :)</p>]]></description>
    <link><![CDATA[http://hynek.me/articles/my-road-to-the-python-commit-bit/]]></link>
    <pubDate>2012-05-19 18:35:00</pubDate>
  </item>
  <item>
    <title><![CDATA[Calvin Spealman: I Read Things On The Internet]]></title>
    <description><![CDATA[It is true, from time to time I read things on the internet. What has been bothering me lately is the feeling that all of these ideas I'm consuming and all of my responses to them are just lost into a sea churning together everything into the unidentifiable paste that comes out of my head.<br />
<br />
<br />
So, I've decided to start logging this. After all, the word "blog" is a shortening of "weblog", a<i> web log</i>, a log of the things you've read on the web. I want this for my own daily readings, both to keep a record for myself (and anyone with an interest) and to note my thoughts, comments, responses, and questions about the things I come across.<br />
<br />
<br />
<a href="http://ironfroggy-reads.tumblr.com/">Ironfroggy Reads Things On The Internet</a> is this new thing. It is a blog on Tumblr, which I find a useful tool for smaller posts and their bookmarklet is perfect for my needs here. I'll be directing the posts to twitter to, as an experiment. Let me know if that turns out annoying.<br />
<br />
<br />
Follow it, if you care to. Mostly its for me, but I believe in transparency by default.<br />
<div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/21332048-3955989040973987635?l=techblog.ironfroggy.com" alt="" /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/RavingTechnoRant?a=h97WPRYdK7U:WeLnF7cBAso:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/RavingTechnoRant?d=yIl2AUoC8zA" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/RavingTechnoRant?a=h97WPRYdK7U:WeLnF7cBAso:63t7Ie-LG7Y"><img src="http://feeds.feedburner.com/~ff/RavingTechnoRant?d=63t7Ie-LG7Y" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/RavingTechnoRant?a=h97WPRYdK7U:WeLnF7cBAso:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/RavingTechnoRant?i=h97WPRYdK7U:WeLnF7cBAso:F7zBnMyn0Lo" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/RavingTechnoRant?a=h97WPRYdK7U:WeLnF7cBAso:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/RavingTechnoRant?d=7Q72WNTAKBA" border="0" /></a> <a href="http://feeds.feedburner.com/~ff/RavingTechnoRant?a=h97WPRYdK7U:WeLnF7cBAso:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/RavingTechnoRant?i=h97WPRYdK7U:WeLnF7cBAso:V_sGLiPBpWU" border="0" /></a>
</div>]]></description>
    <link><![CDATA[http://techblog.ironfroggy.com/2012/05/i-read-things-on-internet.html]]></link>
    <pubDate>2012-05-19 17:02:00</pubDate>
  </item>
  <item>
    <title><![CDATA[Luke Plant: Reasons to love Django, part x of y]]></title>
    <description><![CDATA[<p>I needed to add a boolean field to a model. For many web apps, this typically involves:</p>
<ol>
<li>modifying the model layer, so that the field becomes available as an attribute on retrieved objects, and can be queried against etc.</li>
<li>creating a database migration script that can be run immediately on the development box, and later for staging and production.</li>
<li>running the migration against the development DB.</li>
<li>updating any admin screens for editing the field.</li>
<li>checking the changes and scripts into source control.</li>
<li>deploying - including pushing source code and running migration scripts etc.</li>
</ol>
<p>Using <a href="https://www.djangoproject.com/">Django</a>, from a cold start (no editor/IDE open), this just took me <strong>1 minute 45 seconds of work</strong> for steps 1 - 4, and an additional 45 seconds waiting for step 5, total 2 minutes 30 seconds, and I wasn't rushing.</p>
<p>Step 1 is a one line code addition. Pretty much everything else can and should be generated automatically.</p>
<p>Step 2 is taken care of by a one line command using <a href="http://south.aeracode.org/">South</a>, as is step 3 and the database part of step 6 (which is run de-rigueur from my deployment scripts).</p>
<p>Step 4 is taken care of by Django's admin, which introspects the model and generates the right form for you.</p>
<p>This is one of the reasons I love Django. It's not so much the time it saves, although that is pretty awesome, it's the <em>tedium</em> it saves.</p>
<p>This is also one of the reasons I'm not very tempted by schema-less or schema-light databases, because with Django a nice strict schema brings so little administrative overhead. I was going to have to add <em>something</em> about the change to the model anyway, even if it was only documentation, and having done that in one place, the other additional changes required by a relational DB with strong schema placed virtually no burden on me.</p>
<p>(Of course, things could be more complex on bigger apps, especially if the table is large or sharded. But then again, there's no reason why rolling out your DB change shouldn't be just as automated - it's only the 'waiting' stage that <em>has</em> to take longer for a simple change like adding a column. If the coding/work part is taking much longer than the above example, your tools probably need fixing or replacing.)</p>]]></description>
    <link><![CDATA[http://lukeplant.me.uk/blog/posts/reasons-to-love-django-part-x-of-y/]]></link>
    <pubDate>2012-05-19 14:12:19</pubDate>
  </item>
  <item>
    <title><![CDATA[Twisted Matrix Labs: Congratulations and welcome to Twisted's summer interns]]></title>
    <description><![CDATA[<br />
<p>Twisted is excited to be supporting 4 full-time summer interns from around the world through 2 internship programs this summer.</p>

<h2>Google Summer of Code internships</h2>

<h3>Expanded Endpoints Support, by Ashwini Oruganti (IRC nick ashfall)</h3>
<br />
<p>Ashwini joins us from the Manipal Institute of Technology in Manipal, India. She has already worked on and closed out a number of Twisted tickets and has previously contributed to Evolution and Sugar Labs.</p>

<p>Her project:</p>

<blockquote>
Recently, two new APIs, IStreamServerEndpoint and IStreamClientEndpoint were added to Twisted, for specifying what address the servers should listen for connections and what address a client should connect to, respectively. But not all of the addresses that Twisted supports have this endpoint support added to them; presently endpoint support has been implemented for TCP, SSL and UNIX domain sockets. My project deals with adding more endpoint implementation to Twisted, some involving wrappers around the existing APIs (e.g. serial ports, standard I/O), others involving making fresh APIs where setting up connections was difficult before the addition of the endpoints (e.g. SOCKS and HTTPS proxies).
</blockquote>

<h3>Python 3 preparation, by Vladimir Perić (IRC nick vperic)</h3>
<br />
<p>Vladimir joins us from Czech Technical University in Prague. Last year he was a Google Summer of Code student with SymPy.</p>

<p>His project:</p>

<blockquote>
Python 3 is the future of Python. If Twisted is to see continued usage in the future, it will have to be ported, and rather sooner than later. As Twisted is a large and complicated code-base, this process needs to be done with care, ensuring that any code written remains compatible with the currently supported versions. The test-driven development methodology Twisted uses will ensure no regressions happen and will ease the maintenance of the code-base.
</blockquote>

<h3>Automatic Coding Standard Enforcement, by Raphael Shu (IRC nick zomux)</h3>
<br />
<p>Raphael joins us from Tsukuba University in Japan, where he uses Python daily in his NLP research.</p>

<p>His project:</p>

<blockquote>
Twisted applies certain naming and style standards to all contributed code. Currently, a human reviewer needs to check all of these things. The purpose of this project is to develop a tool which can automatically make these simple, mechanical checks, freeing up human reviewer time to focus on more important aspects of proposed changes. Finally, it will speed up the review process.
</blockquote>

<h2>Software Freedom Conservancy / GNOME Outreach Program internship</h2>

<p>We are also excited to be working with the <a href="http://sfconservancy.org/">Software Freedom Conservancy</a> and the <a href="http://live.gnome.org/GnomeWomen/OutreachProgram2012">GNOME Outreach Program for Women</a> this summer. You can read more about the initiative and our work to encourage diverse participation in open source communities <a href="http://sfconservancy.org/news/2012/mar/27/outreach/">here</a>. Through this initiative we have a 4th paid, full-time internship this summer:</p>

<h3>Improving Twisted Mail and Twisted Core, by Fei Tan (IRC nick argonemyth)</h3>
<br />
<p>Fei joins us from Grand Bay, Mauritius, where she works as a freelance web developer.</p>

<p>She will improve Twisted Mail on a number of fronts, including improving API documentation, adding more examples, adding more HOWTOs, and improved test coverage.</p>

<p>Please join me in welcoming Ashwini, Vladimir, Raphael, and Fei, whose internships start next week. Expect a torrent of code reviews and some record-breaking <a href="http://twistedmatrix.com/highscores/">high scores list</a> stats this summer!</p>

<p>Thank you Google for giving us this paid mentorship opportunity, and thank you to the <a href="https://twitter.com/#!/thepsf">Python Software Foundation</a> for supporting us as our Google Summer of Code umbrella organization.</p><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/1267458971896358542-1164411226954400997?l=labs.twistedmatrix.com" alt="" /></div><img src="http://feeds.feedburner.com/~r/TwistedMatrixLaboratories/~4/3J9GS7GTWVM" height="1" width="1" />]]></description>
    <link><![CDATA[http://feedproxy.google.com/~r/TwistedMatrixLaboratories/~3/3J9GS7GTWVM/congratulations-and-welcome-to-twisteds.html]]></link>
    <pubDate>2012-05-19 11:08:31</pubDate>
  </item>
  <item>
    <title><![CDATA[David Grant: eyefiserver2 - A standalone Eye-Fi Server in python, for linux]]></title>
    <description><![CDATA[<p>I recently forked the defunct eyefiserver project. The new project is called <a href="http://code.google.com/p/eyefiserver2/">eyefiserver2</a>. It is a server for eye-fi cards that runs on Linux using Python, however, it should be possible to run it on any OS, I just haven't tested it on anything other than Linux.</p>]]></description>
    <link><![CDATA[http://www.davidgrant.ca/eyefiserver2_standalone_eyefi_server_python_linux]]></link>
    <pubDate>2012-05-19 07:17:32</pubDate>
  </item>
  <item>
    <title><![CDATA[Mike Driscoll: Creating QR Codes with Python]]></title>
    <description><![CDATA[<p>The other day, I thought it would be fun to create a little program that could generate QR codes and show them onscreen with wxPython. Of course, I wanted to do it all with Python, so after a little looking, I came across 3 candidates:</p>
<ul>
<li><a href="https://github.com/lincolnloop/python-qrcode" target="_blank">python-qrcode</a> on github</li>
<li><a href="http://pyqrcode.sourceforge.net/" target="_blank">pyqrcode</a> on sourceforge and</li>
<li><a href="http://code.google.com/p/pyqrnative/" target="_blank">pyqrnative </a> on Google code</li>
</ul>
<p>I tried python-qrcode and pyqrnative since they worked on Windows as well as Mac and Linux. They also didn&#8217;t require anything except the Python Imaging Library. The pyqrcode project requires several other prerequisites and didn&#8217;t work on Windows, so I didn&#8217;t want to mess with it. I ended up taking some old code based on my <a href="http://www.blog.pythonlibrary.org/2010/03/26/creating-a-simple-photo-viewer-with-wxpython/" target="_blank">Photo Viewer</a> application and modified it slightly to make this a QR Code viewer. If I&#8217;ve piqued your interest, then read on!<span id="more-2310"></span></p>
<h3>Getting Started</h3>
<p>As I noted at the beginning, you will need the <a href="http://www.pythonware.com/products/pil/" target="_blank">Python Imaging Library</a>. We&#8217;ll be using <a href="http://www.wxpython.org" target="_blank">wxPython</a> for the GUI part, so you&#8217;ll need that as well. And you&#8217;ll want to download python-qrcode and pyqrnative. The main difference I have found is that python-qrcode is much faster at generating the images and it generates the type you&#8217;ve probably seen the most of. For some reason, pyqrnative take a lot longer to run and it creates a much denser looking QR code. There may be options for both of these projects that allow you to generate different kinds of codes, but the documentation for either project is abysmal. I ended up using the source and Wingware&#8217;s IDE to traverse the code more than anything else.</p>
<h3>Generating QR Codes</h3>
<p>Anyway, once you have all the prerequisites, you can run the following code and see what Python can do:</p>
<pre class="python"><span>import</span> <span>os</span>
<span>import</span> wx
&nbsp;
<span>try</span>:
    <span>import</span> qrcode
<span>except</span> <span>ImportError</span>:
    qrcode = <span>None</span>
&nbsp;
<span>try</span>:
    <span>import</span> PyQRNative
<span>except</span> <span>ImportError</span>:
    PyQRNative = <span>None</span>
&nbsp;
<span>########################################################################</span>
<span>class</span> QRPanel<span>&#40;</span>wx.<span>Panel</span><span>&#41;</span>:
    <span>&quot;&quot;</span><span>&quot;&quot;</span><span>&quot;&quot;</span>
&nbsp;
    <span>#----------------------------------------------------------------------</span>
    <span>def</span> <span>__init__</span><span>&#40;</span><span>self</span>, parent<span>&#41;</span>:
        <span>&quot;&quot;</span><span>&quot;Constructor&quot;</span><span>&quot;&quot;</span>
        wx.<span>Panel</span>.<span>__init__</span><span>&#40;</span><span>self</span>, parent=parent<span>&#41;</span>
        <span>self</span>.<span>photo_max_size</span> = <span>240</span>
        sp = wx.<span>StandardPaths</span>.<span>Get</span><span>&#40;</span><span>&#41;</span>
        <span>self</span>.<span>defaultLocation</span> = sp.<span>GetDocumentsDir</span><span>&#40;</span><span>&#41;</span>
&nbsp;
        img = wx.<span>EmptyImage</span><span>&#40;</span><span>240</span>,<span>240</span><span>&#41;</span>
        <span>self</span>.<span>imageCtrl</span> = wx.<span>StaticBitmap</span><span>&#40;</span><span>self</span>, wx.<span>ID_ANY</span>,
                                         wx.<span>BitmapFromImage</span><span>&#40;</span>img<span>&#41;</span><span>&#41;</span>
&nbsp;
        qrDataLbl = wx.<span>StaticText</span><span>&#40;</span><span>self</span>, label=<span>&quot;Text to turn into QR Code:&quot;</span><span>&#41;</span>
        <span>self</span>.<span>qrDataTxt</span> = wx.<span>TextCtrl</span><span>&#40;</span><span>self</span>, value=<span>&quot;http://www.mousevspython.com&quot;</span>, size=<span>&#40;</span><span>200</span>,<span>-1</span><span>&#41;</span><span>&#41;</span>
        instructions = <span>&quot;Name QR image file&quot;</span>
        instructLbl = wx.<span>StaticText</span><span>&#40;</span><span>self</span>, label=instructions<span>&#41;</span>
        <span>self</span>.<span>qrPhotoTxt</span> = wx.<span>TextCtrl</span><span>&#40;</span><span>self</span>, size=<span>&#40;</span><span>200</span>,<span>-1</span><span>&#41;</span><span>&#41;</span>
        browseBtn = wx.<span>Button</span><span>&#40;</span><span>self</span>, label=<span>'Change Save Location'</span><span>&#41;</span>
        browseBtn.<span>Bind</span><span>&#40;</span>wx.<span>EVT_BUTTON</span>, <span>self</span>.<span>onBrowse</span><span>&#41;</span>
        defLbl = <span>&quot;Default save location: &quot;</span> + <span>self</span>.<span>defaultLocation</span>
        <span>self</span>.<span>defaultLocationLbl</span> = wx.<span>StaticText</span><span>&#40;</span><span>self</span>, label=defLbl<span>&#41;</span>
&nbsp;
        qrcodeBtn = wx.<span>Button</span><span>&#40;</span><span>self</span>, label=<span>&quot;Create QR with qrcode&quot;</span><span>&#41;</span>
        qrcodeBtn.<span>Bind</span><span>&#40;</span>wx.<span>EVT_BUTTON</span>, <span>self</span>.<span>onUseQrcode</span><span>&#41;</span>
        pyQRNativeBtn = wx.<span>Button</span><span>&#40;</span><span>self</span>, label=<span>&quot;Create QR with PyQRNative&quot;</span><span>&#41;</span>
        pyQRNativeBtn.<span>Bind</span><span>&#40;</span>wx.<span>EVT_BUTTON</span>, <span>self</span>.<span>onUsePyQR</span><span>&#41;</span>
&nbsp;
        <span># Create sizer</span>
        <span>self</span>.<span>mainSizer</span> = wx.<span>BoxSizer</span><span>&#40;</span>wx.<span>VERTICAL</span><span>&#41;</span>
        qrDataSizer = wx.<span>BoxSizer</span><span>&#40;</span>wx.<span>HORIZONTAL</span><span>&#41;</span>
        locationSizer = wx.<span>BoxSizer</span><span>&#40;</span>wx.<span>HORIZONTAL</span><span>&#41;</span>
        qrBtnSizer = wx.<span>BoxSizer</span><span>&#40;</span>wx.<span>VERTICAL</span><span>&#41;</span>
&nbsp;
        qrDataSizer.<span>Add</span><span>&#40;</span>qrDataLbl, <span>0</span>, wx.<span>ALL</span>, <span>5</span><span>&#41;</span>
        qrDataSizer.<span>Add</span><span>&#40;</span><span>self</span>.<span>qrDataTxt</span>, <span>1</span>, wx.<span>ALL</span>|wx.<span>EXPAND</span>, <span>5</span><span>&#41;</span>
        <span>self</span>.<span>mainSizer</span>.<span>Add</span><span>&#40;</span>wx.<span>StaticLine</span><span>&#40;</span><span>self</span>, wx.<span>ID_ANY</span><span>&#41;</span>,
                           <span>0</span>, wx.<span>ALL</span>|wx.<span>EXPAND</span>, <span>5</span><span>&#41;</span>
        <span>self</span>.<span>mainSizer</span>.<span>Add</span><span>&#40;</span>qrDataSizer, <span>0</span>, wx.<span>EXPAND</span><span>&#41;</span>
        <span>self</span>.<span>mainSizer</span>.<span>Add</span><span>&#40;</span><span>self</span>.<span>imageCtrl</span>, <span>0</span>, wx.<span>ALL</span>, <span>5</span><span>&#41;</span>
        locationSizer.<span>Add</span><span>&#40;</span>instructLbl, <span>0</span>, wx.<span>ALL</span>, <span>5</span><span>&#41;</span>
        locationSizer.<span>Add</span><span>&#40;</span><span>self</span>.<span>qrPhotoTxt</span>, <span>0</span>, wx.<span>ALL</span>, <span>5</span><span>&#41;</span>
        locationSizer.<span>Add</span><span>&#40;</span>browseBtn, <span>0</span>, wx.<span>ALL</span>, <span>5</span><span>&#41;</span>
        <span>self</span>.<span>mainSizer</span>.<span>Add</span><span>&#40;</span>locationSizer, <span>0</span>, wx.<span>ALL</span>, <span>5</span><span>&#41;</span>
        <span>self</span>.<span>mainSizer</span>.<span>Add</span><span>&#40;</span><span>self</span>.<span>defaultLocationLbl</span>, <span>0</span>, wx.<span>ALL</span>, <span>5</span><span>&#41;</span>
&nbsp;
        qrBtnSizer.<span>Add</span><span>&#40;</span>qrcodeBtn, <span>0</span>, wx.<span>ALL</span>, <span>5</span><span>&#41;</span>
        qrBtnSizer.<span>Add</span><span>&#40;</span>pyQRNativeBtn, <span>0</span>, wx.<span>ALL</span>, <span>5</span><span>&#41;</span>
        <span>self</span>.<span>mainSizer</span>.<span>Add</span><span>&#40;</span>qrBtnSizer, <span>0</span>, wx.<span>ALL</span>|wx.<span>CENTER</span>, <span>10</span><span>&#41;</span>
&nbsp;
        <span>self</span>.<span>SetSizer</span><span>&#40;</span><span>self</span>.<span>mainSizer</span><span>&#41;</span>
        <span>self</span>.<span>Layout</span><span>&#40;</span><span>&#41;</span>
&nbsp;
    <span>#----------------------------------------------------------------------</span>
    <span>def</span> onBrowse<span>&#40;</span><span>self</span>, event<span>&#41;</span>:
        <span>&quot;&quot;</span><span>&quot;&quot;</span><span>&quot;&quot;</span>
        dlg = wx.<span>DirDialog</span><span>&#40;</span><span>self</span>, <span>&quot;Choose a directory:&quot;</span>,
                           style=wx.<span>DD_DEFAULT_STYLE</span><span>&#41;</span>
        <span>if</span> dlg.<span>ShowModal</span><span>&#40;</span><span>&#41;</span> == wx.<span>ID_OK</span>:
            path = dlg.<span>GetPath</span><span>&#40;</span><span>&#41;</span>
            <span>self</span>.<span>defaultLocation</span> = path
            <span>self</span>.<span>defaultLocationLbl</span>.<span>SetLabel</span><span>&#40;</span><span>&quot;Save location: %s&quot;</span> <span>%</span> path<span>&#41;</span>
        dlg.<span>Destroy</span><span>&#40;</span><span>&#41;</span>
&nbsp;
    <span>#----------------------------------------------------------------------</span>
    <span>def</span> onUseQrcode<span>&#40;</span><span>self</span>, event<span>&#41;</span>:
        <span>&quot;&quot;</span><span>&quot;

https://github.com/lincolnloop/python-qrcode

        &quot;</span><span>&quot;&quot;</span>
        qr = qrcode.<span>QRCode</span><span>&#40;</span>version=<span>1</span>, box_size=<span>10</span>, border=<span>4</span><span>&#41;</span>
        qr.<span>add_data</span><span>&#40;</span><span>self</span>.<span>qrDataTxt</span>.<span>GetValue</span><span>&#40;</span><span>&#41;</span><span>&#41;</span>
        qr.<span>make</span><span>&#40;</span>fit=<span>True</span><span>&#41;</span>
        x = qr.<span>make_image</span><span>&#40;</span><span>&#41;</span>
&nbsp;
        qr_file = <span>os</span>.<span>path</span>.<span>join</span><span>&#40;</span><span>self</span>.<span>defaultLocation</span>, <span>self</span>.<span>qrPhotoTxt</span>.<span>GetValue</span><span>&#40;</span><span>&#41;</span> + <span>&quot;.jpg&quot;</span><span>&#41;</span>
        img_file = <span>open</span><span>&#40;</span>qr_file, <span>'wb'</span><span>&#41;</span>
        x.<span>save</span><span>&#40;</span>img_file, <span>'JPEG'</span><span>&#41;</span>
        img_file.<span>close</span><span>&#40;</span><span>&#41;</span>
        <span>self</span>.<span>showQRCode</span><span>&#40;</span>qr_file<span>&#41;</span>
&nbsp;
    <span>#----------------------------------------------------------------------</span>
    <span>def</span> onUsePyQR<span>&#40;</span><span>self</span>, event<span>&#41;</span>:
        <span>&quot;&quot;</span><span>&quot;

http://code.google.com/p/pyqrnative/

        &quot;</span><span>&quot;&quot;</span>
        qr = PyQRNative.<span>QRCode</span><span>&#40;</span><span>20</span>, PyQRNative.<span>QRErrorCorrectLevel</span>.<span>L</span><span>&#41;</span>
        qr.<span>addData</span><span>&#40;</span><span>self</span>.<span>qrDataTxt</span>.<span>GetValue</span><span>&#40;</span><span>&#41;</span><span>&#41;</span>
        qr.<span>make</span><span>&#40;</span><span>&#41;</span>
        im = qr.<span>makeImage</span><span>&#40;</span><span>&#41;</span>
&nbsp;
        qr_file = <span>os</span>.<span>path</span>.<span>join</span><span>&#40;</span><span>self</span>.<span>defaultLocation</span>, <span>self</span>.<span>qrPhotoTxt</span>.<span>GetValue</span><span>&#40;</span><span>&#41;</span> + <span>&quot;.jpg&quot;</span><span>&#41;</span>
        img_file = <span>open</span><span>&#40;</span>qr_file, <span>'wb'</span><span>&#41;</span>
        im.<span>save</span><span>&#40;</span>img_file, <span>'JPEG'</span><span>&#41;</span>
        img_file.<span>close</span><span>&#40;</span><span>&#41;</span>
        <span>self</span>.<span>showQRCode</span><span>&#40;</span>qr_file<span>&#41;</span>
&nbsp;
    <span>#----------------------------------------------------------------------</span>
    <span>def</span> showQRCode<span>&#40;</span><span>self</span>, filepath<span>&#41;</span>:
        <span>&quot;&quot;</span><span>&quot;&quot;</span><span>&quot;&quot;</span>
        img = wx.<span>Image</span><span>&#40;</span>filepath, wx.<span>BITMAP_TYPE_ANY</span><span>&#41;</span>
        <span># scale the image, preserving the aspect ratio</span>
        W = img.<span>GetWidth</span><span>&#40;</span><span>&#41;</span>
        H = img.<span>GetHeight</span><span>&#40;</span><span>&#41;</span>
        <span>if</span> W <span>&gt;</span> H:
            NewW = <span>self</span>.<span>photo_max_size</span>
            NewH = <span>self</span>.<span>photo_max_size</span> <span>*</span> H / W
        <span>else</span>:
            NewH = <span>self</span>.<span>photo_max_size</span>
            NewW = <span>self</span>.<span>photo_max_size</span> <span>*</span> W / H
        img = img.<span>Scale</span><span>&#40;</span>NewW,NewH<span>&#41;</span>
&nbsp;
        <span>self</span>.<span>imageCtrl</span>.<span>SetBitmap</span><span>&#40;</span>wx.<span>BitmapFromImage</span><span>&#40;</span>img<span>&#41;</span><span>&#41;</span>
        <span>self</span>.<span>Refresh</span><span>&#40;</span><span>&#41;</span>
&nbsp;
&nbsp;
<span>########################################################################</span>
<span>class</span> QRFrame<span>&#40;</span>wx.<span>Frame</span><span>&#41;</span>:
    <span>&quot;&quot;</span><span>&quot;&quot;</span><span>&quot;&quot;</span>
&nbsp;
    <span>#----------------------------------------------------------------------</span>
    <span>def</span> <span>__init__</span><span>&#40;</span><span>self</span><span>&#41;</span>:
        <span>&quot;&quot;</span><span>&quot;Constructor&quot;</span><span>&quot;&quot;</span>
        wx.<span>Frame</span>.<span>__init__</span><span>&#40;</span><span>self</span>, <span>None</span>, title=<span>&quot;QR Code Viewer&quot;</span>, size=<span>&#40;</span><span>550</span>,<span>500</span><span>&#41;</span><span>&#41;</span>
        panel = QRPanel<span>&#40;</span><span>self</span><span>&#41;</span>
&nbsp;
<span>if</span> __name__ == <span>&quot;__main__&quot;</span>:
    app = wx.<span>App</span><span>&#40;</span><span>False</span><span>&#41;</span>
    frame = QRFrame<span>&#40;</span><span>&#41;</span>
    frame.<span>Show</span><span>&#40;</span><span>&#41;</span>
    app.<span>MainLoop</span><span>&#40;</span><span>&#41;</span></pre>
<p>The code for changing and showing the picture is explained in the previous article I wrote (and linked to above), so the only parts that you&#8217;ll probably care about are the two methods for generating the QR codes: <strong>onUseQrcode </strong>and <strong>onUsePyQR</strong>. I just took some examples from their respective websites and modified them slightly to create the QR code images. They&#8217;re very straight-forward, but not well documented, so I can&#8217;t really tell you what&#8217;s going on. Sadly at the time of this writing, the code for these projects is seriously lacking in docstrings, with only a few here and there. Still, I was able to generate some decent QR codes. The following was done using python-qrcode:</p>
<p><a href="http://www.blog.pythonlibrary.org/wp-content/uploads/2012/05/qrcode1.png"><img src="http://www.blog.pythonlibrary.org/wp-content/uploads/2012/05/qrcode1.png" alt="" title="qrcode1" width="550" height="500" class="aligncenter size-full wp-image-2314" /></a></p>
<p>As you can see, it&#8217;s a pretty standard code. The next one is created with PyQRNative and is much denser looking:</p>
<p><a href="http://www.blog.pythonlibrary.org/wp-content/uploads/2012/05/qrcode2.png"><img src="http://www.blog.pythonlibrary.org/wp-content/uploads/2012/05/qrcode2.png" alt="" title="qrcode2" width="550" height="500" class="aligncenter size-full wp-image-2315" /></a></p>
<p>I tried scanning both images with my Android cell phone&#8217;s barcode scanning application and both QR codes were read correctly by it. So if you&#8217;re in need of generating QR code images for your project, I hope one of these projects will fit your needs!</p>
<h3>Source Code</h3>
<ul>
<li><a href="http://www.blog.pythonlibrary.org/wp-content/uploads/2012/05/QRCodeViewer.zip">QRCodeViewer.zip</a></li>
</ul>]]></description>
    <link><![CDATA[http://www.blog.pythonlibrary.org/2012/05/18/creating-qr-codes-with-python/]]></link>
    <pubDate>2012-05-18 22:46:32</pubDate>
  </item>
  <item>
    <title><![CDATA[Shannon -jj Behrens: Code Reuse has Finally Arrived...Obviously!]]></title>
    <description><![CDATA[<div dir="ltr"><p>I got into a discussion about code reuse with my co-worker, Jarek.  I remember reading books on object oriented programming from a few decades ago in which OOP promised to increase code reuse.  A lot of people doubted that serious code reuse would ever happen.  OOP suggested that code reuse would be possible by reusing and subclassing existing classes.  I even remember hearing C++ programmers talk about purchasing libraries of useful classes.</p> <p>To some degree, this did actually happen.  For instance, QT is a wonderful library for C++, and it certainly makes coding in C++ a lot easier.  It was even proprietary up until a few years ago.  Library reuse also happened via language-specific package sites such as CPAN (for Perl), PyPI (for Python), and a range of sites for Ruby.  Furthermore, most languages come with a lot more stuff built in these days.  For instance, compare Python's standard library ("batteries included") with that of C.</p> <p>However, compared to decades ago, there is less of an emphasis on class-level reuse these days.  For instance, rather than trying to code classes that will be flexible enough to solve tomorrow's problems, agile programmers suggests you write your code in such a way that you will be able to modify it to solve tomorrow's problems (with an emphasis on tests that will prevent regressions when you modify the existing code).</p> <p>These days, rather than focusing on class-level reuse, we've achieved reuse via RESTful web services (and variations thereof) as well as via open source stacks.  RESTful web services are usually closed source and proprietary.  However, they have a lot of benefits.  For instance, they're language agnostic.  It's also a lot easier to control access to a RESTful Web Service than it is to a class library.  This permits good authorization controls and various monetization strategies.</p> <p>As I mentioned before, another place where we see a lot of reuse is in the open source stack.  Just as Taco Bell has a million things on the menu that are all made from the same 10 ingredients, there are a million startups out there all based on the same stack of open source software.  We even have a word for it--LAMP.  Sure, there are variations of this--PostgreSQL instead of MySQL, Nginx instead of Apache, Python and Ruby instead of PHP--however, the fact remains that a lot of startups are only possible because of the tremendous amount of code that is available for reuse.</p> <p>Hence, it's clear that code reuse arrived during the last 10-20 years.  It didn't come exactly as we expected, but it's definitely here.</p></div><div class="blogger-post-footer"><img width="1" height="1" src="https://blogger.googleusercontent.com/tracker/11788780-3516087353225973134?l=jjinux.blogspot.com" alt="" /></div>]]></description>
    <link><![CDATA[http://jjinux.blogspot.com/2012/05/code-reuse-has-finally-arrivedobviously.html]]></link>
    <pubDate>2012-05-18 20:07:13</pubDate>
  </item>
</channel>
</rss>

