<?xml version="1.0"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">

<channel>
	<title>Planet Python</title>
	<link>http://planet.python.org/</link>
	<language>en</language>
	<description>Planet Python - http://planet.python.org/</description>

<item>
	<title>Mike Driscoll: wxPython: All about Menus</title>
	<guid>http://www.blog.pythonlibrary.org/2012/02/14/wxpython-all-about-menus/</guid>
	<link>http://www.blog.pythonlibrary.org/2012/02/14/wxpython-all-about-menus/</link>
	<description>&lt;p&gt;Menus are ubiquitous. They&amp;#8217;re in almost all desktop programs. You use them for editing preferences or configuring your program. In wxPython, there are several menu options to choose from. The most familiar is probably wx.Menu. But there are are popup menus and a pure Python implementation known as FlatMenu. We will just be covering wx.Menu and popup menus here because they&amp;#8217;re related to each other. FlatMenu also includes a toolbar API, so you&amp;#8217;ll have to wait for another article that will just cover that widget all by itself. Let&amp;#8217;s get this menu party started!&lt;span id=&quot;more-2207&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;A Simple Menu Example&lt;/h3&gt;
&lt;p&gt;
&lt;p&gt;
&lt;a href=&quot;http://www.blog.pythonlibrary.org/wp-content/uploads/2012/02/menu_one.png&quot;&gt;&lt;img src=&quot;http://www.blog.pythonlibrary.org/wp-content/uploads/2012/02/menu_one-300x187.png&quot; alt=&quot;&quot; title=&quot;menu_one.png&quot; width=&quot;300&quot; height=&quot;187&quot; class=&quot;aligncenter size-medium wp-image-2208&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ll start with something really simple: a menu with just an Exit MenuItem. Here&amp;#8217;s the code:&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;import&lt;/span&gt; wx
&amp;nbsp;
&lt;span&gt;########################################################################&lt;/span&gt;
&lt;span&gt;class&lt;/span&gt; MyForm&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;Frame&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; &lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;Constructor&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        wx.&lt;span&gt;Frame&lt;/span&gt;.&lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, &lt;span&gt;None&lt;/span&gt;, title=&lt;span&gt;&amp;quot;wx.Menu Tutorial&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;panel&lt;/span&gt; = wx.&lt;span&gt;Panel&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, wx.&lt;span&gt;ID_ANY&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        menuBar = wx.&lt;span&gt;MenuBar&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        fileMenu = wx.&lt;span&gt;Menu&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        exitMenuItem = fileMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, &lt;span&gt;&amp;quot;Exit&amp;quot;&lt;/span&gt;,
                                       &lt;span&gt;&amp;quot;Exit the application&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        menuBar.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;fileMenu, &lt;span&gt;&amp;quot;&amp;amp;File&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;Bind&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;EVT_MENU&lt;/span&gt;, &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;onExit&lt;/span&gt;, exitMenuItem&lt;span&gt;&amp;#41;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;SetMenuBar&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;menuBar&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; onExit&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, event&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;Close&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
&lt;span&gt;# Run the program&lt;/span&gt;
&lt;span&gt;if&lt;/span&gt; __name__ == &lt;span&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;:
    app = wx.&lt;span&gt;App&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;False&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    frame = MyForm&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;.&lt;span&gt;Show&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    app.&lt;span&gt;MainLoop&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#8217;s break this down a little. To create the menubar, we instantiate an instance of wx.MenuBar. Then we create a an instance of wx.Menu that we call &lt;strong&gt;filemenu&lt;/strong&gt;. Finally, to add the &amp;#8220;Exit&amp;#8221; item, we append some data to it. In essence, we are appending a wx.MenuItem, but this is kind of a shortcut since we didn&amp;#8217;t actually create a wx.MenuItem instance first. We&amp;#8217;ll show how to do that in our next example though. Note that when we append the item, we have to pass an id, a label string and a status string. That last one will show up in the Status bar when you hover over the menu item, assuming you have a status bar. Note that to attach an event handler to a menu item, you need use the EVT_MENU event and bind it to the frame. Next we append the Menu itself to the MenuBar object and pass it a string too, which in this case is &amp;#8220;File&amp;#8221;. Finally we call the frame&amp;#8217;s &lt;strong&gt;SetMenuBar&lt;/strong&gt; method to attach the menu bar to the frame. &lt;/p&gt;
&lt;h3&gt;Adding a Picture to a Menu&lt;/h3&gt;
&lt;p&gt;
&lt;p&gt;
That&amp;#8217;s all there is to creating a menu! Now let&amp;#8217;s look at a more complex example! &lt;em&gt;Note: to follow the example below, you&amp;#8217;ll need to use your own image file.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.blog.pythonlibrary.org/wp-content/uploads/2012/02/menu_two.png&quot;&gt;&lt;img src=&quot;http://www.blog.pythonlibrary.org/wp-content/uploads/2012/02/menu_two-300x187.png&quot; alt=&quot;&quot; title=&quot;menu_two.png&quot; width=&quot;300&quot; height=&quot;187&quot; class=&quot;aligncenter size-medium wp-image-2213&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;import&lt;/span&gt; wx
&amp;nbsp;
&lt;span&gt;########################################################################&lt;/span&gt;
&lt;span&gt;class&lt;/span&gt; MyForm&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;Frame&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; &lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;Constructor&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        wx.&lt;span&gt;Frame&lt;/span&gt;.&lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, &lt;span&gt;None&lt;/span&gt;, title=&lt;span&gt;&amp;quot;wx.Menu Tutorial&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;panel&lt;/span&gt; = wx.&lt;span&gt;Panel&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, wx.&lt;span&gt;ID_ANY&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# create the menubar&lt;/span&gt;
        menuBar = wx.&lt;span&gt;MenuBar&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# create the first menu (starting on left)&lt;/span&gt;
        carMenu = wx.&lt;span&gt;Menu&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        carMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;101&lt;/span&gt;, &lt;span&gt;&amp;quot;&amp;amp;Ford&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;An American Automaker&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        carMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;102&lt;/span&gt;, &lt;span&gt;&amp;quot;&amp;amp;Nissan&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        carMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;103&lt;/span&gt;, &lt;span&gt;&amp;quot;&amp;amp;Toyota&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;Buy Japanese!&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        carMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;104&lt;/span&gt;, &lt;span&gt;&amp;quot;&amp;amp;Close&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;Close the application&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# add a picture to a menu&lt;/span&gt;
        picMenu = wx.&lt;span&gt;Menu&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        item = wx.&lt;span&gt;MenuItem&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;picMenu, wx.&lt;span&gt;ID_ANY&lt;/span&gt;, &lt;span&gt;&amp;quot;Snake&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;This menu has a picture!&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        img = wx.&lt;span&gt;Image&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'snake32.bmp'&lt;/span&gt;, wx.&lt;span&gt;BITMAP_TYPE_ANY&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        item.&lt;span&gt;SetBitmap&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;BitmapFromImage&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;img&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        picMenu.&lt;span&gt;AppendItem&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;item&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# add menus to menubar&lt;/span&gt;
        menuBar.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;carMenu, &lt;span&gt;&amp;quot;&amp;amp;Vehicles&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        menuBar.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;picMenu, &lt;span&gt;&amp;quot;&amp;amp;Picture&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;SetMenuBar&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;menuBar&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; onExit&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, event&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;Close&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
&lt;span&gt;# Run the program&lt;/span&gt;
&lt;span&gt;if&lt;/span&gt; __name__ == &lt;span&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;:
    app = wx.&lt;span&gt;App&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;False&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    frame = MyForm&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;.&lt;span&gt;Show&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    app.&lt;span&gt;MainLoop&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This example is similar to the first one. The main difference is that we add multiple items to out &lt;strong&gt;File &lt;/strong&gt;menu and we have two menus. Note that this time, we actually specify our ID numbers explicitly. This usually isn&amp;#8217;t recommended as you might accidentally shadow one of wx&amp;#8217;s required IDs. However, you do see examples of this from time to time on the web, so you should be aware of this practice. The next big difference doesn&amp;#8217;t come until we get to the &lt;strong&gt;picMenu&lt;/strong&gt;. Here we actually create a wx.MenuItem and add a picture to it via wx.Image and the MenuItem&amp;#8217;s &lt;strong&gt;SetBitmap&lt;/strong&gt; method. The rest is pretty much the same.&lt;/p&gt;
&lt;p&gt;Now we will spend some time looking at how to add radio and check buttons to our menu.&lt;/p&gt;
&lt;h3&gt;Adding Radio or Check Buttons&lt;/h3&gt;
&lt;p&gt;
&lt;p&gt;
&lt;a href=&quot;http://www.blog.pythonlibrary.org/wp-content/uploads/2012/02/menu_check.png&quot;&gt;&lt;img src=&quot;http://www.blog.pythonlibrary.org/wp-content/uploads/2012/02/menu_check-300x187.png&quot; alt=&quot;&quot; title=&quot;menu_check.png&quot; width=&quot;300&quot; height=&quot;187&quot; class=&quot;aligncenter size-medium wp-image-2215&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Adding a radio or check button to your menu is actually pretty easy. Let&amp;#8217;s take a moment and see how it&amp;#8217;s done!&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# radiocheck.py&lt;/span&gt;
&lt;span&gt;import&lt;/span&gt; wx
&amp;nbsp;
&lt;span&gt;########################################################################&lt;/span&gt;
&lt;span&gt;class&lt;/span&gt; MyForm&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;Frame&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; &lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;Constructor&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        wx.&lt;span&gt;Frame&lt;/span&gt;.&lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, &lt;span&gt;None&lt;/span&gt;, title=&lt;span&gt;&amp;quot;wx.Menu Tutorial&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;panel&lt;/span&gt; = wx.&lt;span&gt;Panel&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, wx.&lt;span&gt;ID_ANY&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# Create menu bar&lt;/span&gt;
        menuBar = wx.&lt;span&gt;MenuBar&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# Create radio menu&lt;/span&gt;
        radioMenu = wx.&lt;span&gt;Menu&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        idleItem = radioMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, &lt;span&gt;&amp;quot;IDLE&amp;quot;&lt;/span&gt;,
                                   &lt;span&gt;&amp;quot;a Python shell using tcl/tk as GUI&amp;quot;&lt;/span&gt;,
                                   wx.&lt;span&gt;ITEM_RADIO&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        pyCrustItem = radioMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;,&lt;span&gt;&amp;quot;PyCrust&amp;quot;&lt;/span&gt;,
                                      &lt;span&gt;&amp;quot;a Python shell using wxPython as GUI&amp;quot;&lt;/span&gt;,
                                      wx.&lt;span&gt;ITEM_RADIO&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        psiItem = radioMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, &lt;span&gt;&amp;quot;psi&amp;quot;&lt;/span&gt;,
                                  &lt;span&gt;&amp;quot;a simple Python shell using wxPython as GUI&amp;quot;&lt;/span&gt;,
                                  wx.&lt;span&gt;ITEM_RADIO&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        menuBar.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;radioMenu, &lt;span&gt;&amp;quot;&amp;amp;Radio&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# create check menu&lt;/span&gt;
        checkMenu = wx.&lt;span&gt;Menu&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        wgItem = checkMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, &lt;span&gt;&amp;quot;Wells Fargo&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;, wx.&lt;span&gt;ITEM_CHECK&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        citiItem = checkMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, &lt;span&gt;&amp;quot;Citibank&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;, wx.&lt;span&gt;ITEM_CHECK&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        geItem = checkMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, &lt;span&gt;&amp;quot;GE Money Bank&amp;quot;&lt;/span&gt;, &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;, wx.&lt;span&gt;ITEM_CHECK&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        menuBar.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;checkMenu, &lt;span&gt;&amp;quot;&amp;amp;Check&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# Attach menu bar to frame&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;SetMenuBar&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;menuBar&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
&lt;span&gt;# Run the program&lt;/span&gt;
&lt;span&gt;if&lt;/span&gt; __name__ == &lt;span&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;:
    app = wx.&lt;span&gt;App&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;False&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    frame = MyForm&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;.&lt;span&gt;Show&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    app.&lt;span&gt;MainLoop&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Yes, as you can see, all you have to do is add a wx.ITEM_RADIO or wx.ITEM_CHECK flag as the &lt;strong&gt;kind &lt;/strong&gt;parameter, which is the 4th parameter. Why is it called &amp;#8220;kind&amp;#8221; rather than &amp;#8220;style&amp;#8221; like other widgets? Well, while discussing this on the wxPython IRC channel, Robin Dunn (creator of wxPython) pointed out that it may be because these are different kinds of menu items. &lt;/p&gt;
&lt;h3&gt;Sub-Menus&lt;/h3&gt;
&lt;p&gt;
&lt;p&gt;
The wxPython library also supports sub-menus. Here&amp;#8217;s a really simple example to show you how it&amp;#8217;s done.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# submenu.py&lt;/span&gt;
&lt;span&gt;import&lt;/span&gt; wx
&amp;nbsp;
&lt;span&gt;########################################################################&lt;/span&gt;
&lt;span&gt;class&lt;/span&gt; MyForm&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;Frame&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; &lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;Constructor&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        wx.&lt;span&gt;Frame&lt;/span&gt;.&lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, &lt;span&gt;None&lt;/span&gt;, title=&lt;span&gt;&amp;quot;wx.Menu Tutorial&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;panel&lt;/span&gt; = wx.&lt;span&gt;Panel&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, wx.&lt;span&gt;ID_ANY&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        menuBar = wx.&lt;span&gt;MenuBar&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        fileMenu = wx.&lt;span&gt;Menu&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        openMenuItem = fileMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, &lt;span&gt;&amp;quot;Open&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# create a submenu&lt;/span&gt;
        subMenu = wx.&lt;span&gt;Menu&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        historyMenuItem = subMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, &lt;span&gt;&amp;quot;Show History&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        fileMenu.&lt;span&gt;AppendMenu&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, &lt;span&gt;&amp;quot;History&amp;quot;&lt;/span&gt;, subMenu&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        exitMenuItem = fileMenu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;, &lt;span&gt;&amp;quot;Exit&amp;quot;&lt;/span&gt;,
                                       &lt;span&gt;&amp;quot;Exit the application&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        menuBar.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;fileMenu, &lt;span&gt;&amp;quot;&amp;amp;File&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;Bind&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;EVT_MENU&lt;/span&gt;, &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;onExit&lt;/span&gt;, exitMenuItem&lt;span&gt;&amp;#41;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;SetMenuBar&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;menuBar&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; onExit&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, event&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;Close&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
&lt;span&gt;# Run the program&lt;/span&gt;
&lt;span&gt;if&lt;/span&gt; __name__ == &lt;span&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;:
    app = wx.&lt;span&gt;App&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;False&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    frame = MyForm&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;.&lt;span&gt;Show&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    app.&lt;span&gt;MainLoop&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The key here is that instead of using the filemenu&amp;#8217;s Append method, we instead use its AppendMenu method. As the name implies, it allows the programmer to actually append a menu instead of a menu item. Yup, that&amp;#8217;s it!&lt;/p&gt;
&lt;h3&gt;Pop-up Menus (AKA: ContextMenus)&lt;/h3&gt;
&lt;p&gt;
&lt;p&gt;
Pop-up menus are the kind you see when you right-click on a link in a browser or on a file. They are also known as Context Menus. Here is a fairly trivial example for you to study:&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;# submenu.py&lt;/span&gt;
&lt;span&gt;import&lt;/span&gt; wx
&amp;nbsp;
&lt;span&gt;########################################################################&lt;/span&gt;
&lt;span&gt;class&lt;/span&gt; MyForm&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;Frame&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
    &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; &lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;Constructor&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        wx.&lt;span&gt;Frame&lt;/span&gt;.&lt;span&gt;__init__&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, &lt;span&gt;None&lt;/span&gt;, title=&lt;span&gt;&amp;quot;Popup Menu Tutorial&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        panel = wx.&lt;span&gt;Panel&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, wx.&lt;span&gt;ID_ANY&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        lbl = wx.&lt;span&gt;StaticText&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;panel, label=&lt;span&gt;&amp;quot;Right click anywhere!&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;Bind&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;EVT_CONTEXT_MENU&lt;/span&gt;, &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;onContext&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; onContext&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, event&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;
        Create and show a Context Menu
        &amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# only do this part the first time so the events are only bound once &lt;/span&gt;
        &lt;span&gt;if&lt;/span&gt; &lt;span&gt;not&lt;/span&gt; &lt;span&gt;hasattr&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, &lt;span&gt;&amp;quot;popupID1&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;:
            &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;popupID1&lt;/span&gt; = wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
            &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;itemTwoId&lt;/span&gt; = wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
            &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;itemThreeId&lt;/span&gt; = wx.&lt;span&gt;NewId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
            &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;Bind&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;EVT_MENU&lt;/span&gt;, &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;onPopup&lt;/span&gt;, &lt;span&gt;id&lt;/span&gt;=&lt;span&gt;self&lt;/span&gt;.&lt;span&gt;popupID1&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
            &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;Bind&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;EVT_MENU&lt;/span&gt;, &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;onPopup&lt;/span&gt;, &lt;span&gt;id&lt;/span&gt;=&lt;span&gt;self&lt;/span&gt;.&lt;span&gt;itemTwoId&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
            &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;Bind&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;wx.&lt;span&gt;EVT_MENU&lt;/span&gt;, &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;onExit&lt;/span&gt;, &lt;span&gt;id&lt;/span&gt;=&lt;span&gt;self&lt;/span&gt;.&lt;span&gt;itemThreeId&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# build the menu&lt;/span&gt;
        menu = wx.&lt;span&gt;Menu&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        itemOne = menu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;.&lt;span&gt;popupID1&lt;/span&gt;, &lt;span&gt;&amp;quot;ItemOne&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        itemTwo = menu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;.&lt;span&gt;itemTwoId&lt;/span&gt;, &lt;span&gt;&amp;quot;ItemTwo&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        itemThree = menu.&lt;span&gt;Append&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;.&lt;span&gt;itemThreeId&lt;/span&gt;, &lt;span&gt;&amp;quot;Exit&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
        &lt;span&gt;# show the popup menu&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;PopupMenu&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;menu&lt;span&gt;&amp;#41;&lt;/span&gt;
        menu.&lt;span&gt;Destroy&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; onExit&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, event&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;
        Exit program
        &amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span&gt;self&lt;/span&gt;.&lt;span&gt;Close&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
    &lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
    &lt;span&gt;def&lt;/span&gt; onPopup&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;self&lt;/span&gt;, event&lt;span&gt;&amp;#41;&lt;/span&gt;:
        &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;
        Print the label of the menu item selected
        &amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
        itemId = event.&lt;span&gt;GetId&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        menu = event.&lt;span&gt;GetEventObject&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
        menuItem = menu.&lt;span&gt;FindItemById&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;itemId&lt;span&gt;&amp;#41;&lt;/span&gt;
        &lt;span&gt;print&lt;/span&gt; menuItem.&lt;span&gt;GetLabel&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&lt;span&gt;#----------------------------------------------------------------------&lt;/span&gt;
&lt;span&gt;# Run the program&lt;/span&gt;
&lt;span&gt;if&lt;/span&gt; __name__ == &lt;span&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;:
    app = wx.&lt;span&gt;App&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;False&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    frame = MyForm&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;.&lt;span&gt;Show&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    app.&lt;span&gt;MainLoop&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;To begin, we bind wx.EVT_CONTEXT_MENU to the frame. This allows us to right-click anywhere and fire the context menu event, which will create and show our popup menu. The code in the &lt;strong&gt;onContext&lt;/strong&gt; method is based loosely on the wxPython demo for the popup menu. As you can see, we use a conditional statement to check if we&amp;#8217;ve already bound the menu events. If we have, we don&amp;#8217;t bind them again. Next we create our menu in much the same way as before. Finally, we call the frame&amp;#8217;s &lt;strong&gt;PopupMenu&lt;/strong&gt; method and pass it our new menu. This will show the menu to the user. When the user clicks on a menu item, it will fire an event and the menu will be destroyed.&lt;/p&gt;
&lt;p&gt;The first two menu items are both bound to our &lt;strong&gt;onPopup&lt;/strong&gt; method. This allows us to see how we can get access to the Menu and the MenuItem attributes. You can get the menu&amp;#8217;s id with the event and the Menu itself with the event&amp;#8217;s GetEventObject method. Then you can use the menu&amp;#8217;s FindItemById method to get a handle to the menu item itself. Finally we print out the menu item&amp;#8217;s label.&lt;/p&gt;
&lt;h3&gt;Wrapping Up&lt;/h3&gt;
&lt;p&gt;
&lt;p&gt;
Now you should know most of the menu methods and how to create them, bind events and make different kinds of menu items. You even know how to create popup menus! Now you can make your applications have fancy menus too.&lt;/p&gt;
&lt;h3&gt;Further Reading&lt;/h3&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.blog.pythonlibrary.org/2008/07/02/wxpython-working-with-menus-toolbars-and-accelerators/&quot; title=&quot;wxPython: Working with Menus, Toolbars and Accelerators&quot; target=&quot;_blank&quot;&gt;wxPython: Working with Menus, Toolbars and Accelerators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Working with Menus &amp;#8211; &lt;a href=&quot;http://wiki.wxpython.org/WorkingWithMenus&quot; target=&quot;_blank&quot;&gt;wxPython Wiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Menus and Toolbars &amp;#8211; &lt;a href=&quot;http://zetcode.com/wxpython/menustoolbars/&quot; target=&quot;_blank&quot;&gt;Zetcode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Source&lt;/h3&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.blog.pythonlibrary.org/wp-content/uploads/2012/02/menus.zip&quot;&gt;menus.zip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.blog.pythonlibrary.org/wp-content/uploads/2012/02/menus.tar&quot;&gt;menus.tar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 14 Feb 2012 20:16:01 +0000</pubDate>
</item>
<item>
	<title>Python Diary: Too many micro webframeworks</title>
	<guid>http://www.pythondiary.com/blog/Feb.14,2012/too-many-micro-webframeworks.html</guid>
	<link>http://www.pythondiary.com/blog/Feb.14,2012/too-many-micro-webframeworks.html</link>
	<description>&lt;p&gt;There is a large amount of Python micro web frameworks out in the wild, and some of them feel similar to eachother, at least when I first approach them.  I plan on going through a few of these micro web frameworks to see what the exact differences are.  I will not be comparing them to full frameworks such as &lt;a href=&quot;http://www.pythondiary.com/packages/django.html&quot;&gt;Django&lt;/a&gt; or &lt;a href=&quot;http://www.pythondiary.com/packages/web2py.html&quot;&gt;Web2py&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;http://www.pythondiary.com/packages/bottle.html&quot;&gt;Bottle&lt;/a&gt;&lt;/h3&gt;
&lt;a href=&quot;http://c286041.r41.cf1.rackcdn.com/blog_image/bottle.png&quot;&gt;&lt;img src=&quot;http://c286041.r41.cf1.rackcdn.com/blog_image/bottle.png&quot; border=&quot;0&quot; width=&quot;100&quot; height=&quot;100&quot; /&gt;&lt;/a&gt;
&lt;p&gt;First up, &lt;a href=&quot;http://www.pythondiary.com/packages/bottle.html&quot;&gt;Bottle&lt;/a&gt;.  It is very micro in that it comes in a single Py file and is very portable across platforms.  If you need a simple Python web app running on say an embedded system with very low resources and disk space, this will be a good option for you.  Here is a snippet of code from their home page of an example application:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;bottle&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'/hello/:name'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'World'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'&amp;lt;b&amp;gt;Hello &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;!&amp;lt;/b&amp;gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'localhost'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Simple, is it not.  One could deploy a Python console application which merely displays output for diagnose of a server or heartbeat in a matter of minutes.  I wouldn't recommend it for full web applications, but no one is stopping you.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;http://www.pythondiary.com/packages/web-dot-py.html&quot;&gt;web.py&lt;/a&gt;&lt;/h3&gt;
&lt;a href=&quot;http://c286041.r41.cf1.rackcdn.com/blog_image/webpy.gif&quot;&gt;&lt;img src=&quot;http://c286041.r41.cf1.rackcdn.com/blog_image/webpy.gif&quot; border=&quot;0&quot; width=&quot;100&quot; height=&quot;100&quot; /&gt;&lt;/a&gt;
&lt;p&gt;Next we have &lt;a href=&quot;http://www.pythondiary.com/packages/web-dot-py.html&quot;&gt;web.py&lt;/a&gt;.  I have heard many good things about this micro framework, that doesn't make it sounds so micro.  A good advantage of this web framework is the ability to separate the requests from both &lt;b&gt;GET&lt;/b&gt; and &lt;b&gt;POST&lt;/b&gt;.  This is great when you need to develop an application which depends on the type of request coming through, such as a REST API.  Here is a snippet from their home page:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;web&lt;/span&gt;
        
&lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;'/(.*)'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'hello'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;web&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;globals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;        
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; 
            &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'World'&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'Hello, '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'!'&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A little more complex than &lt;a href=&quot;http://www.pythondiary.com/packages/bottle.html&quot;&gt;Bottle&lt;/a&gt;, but it's still simpler than say &lt;a href=&quot;http://www.pythondiary.com/packages/django.html&quot;&gt;Django&lt;/a&gt; or &lt;a href=&quot;http://www.pythondiary.com/packages/web2py.html&quot;&gt;Web2py&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;http://www.pythondiary.com/packages/flask.html&quot;&gt;Flask&lt;/a&gt;&lt;/h3&gt;
&lt;a href=&quot;http://c286041.r41.cf1.rackcdn.com/blog_image/flask.png&quot;&gt;&lt;img src=&quot;http://c286041.r41.cf1.rackcdn.com/blog_image/flask.png&quot; border=&quot;0&quot; width=&quot;100&quot; height=&quot;100&quot; /&gt;&lt;/a&gt;
&lt;p&gt;Looking for something even simpler than &lt;a href=&quot;http://www.pythondiary.com/packages/bottle.html&quot;&gt;Bottle&lt;/a&gt;?  Try &lt;a href=&quot;http://www.pythondiary.com/packages/flask.html&quot;&gt;Flask&lt;/a&gt;, there are less imports to remember, but it is ever so similar to &lt;a href=&quot;http://www.pythondiary.com/packages/bottle.html&quot;&gt;Bottle&lt;/a&gt;.  But, it comes with more than bottle, so you will have more than a single file to work with.  It comes with the &lt;a href=&quot;http://www.pythondiary.com/packages/jinja2.html&quot;&gt;Jinja2&lt;/a&gt; template engine, RESTful dispatching, and other goodies that other micro frameworks lack.  Here's a snippet from their homepage:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;flask&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Flask&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Flask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@app.route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Hello World!&amp;quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notice how similar this code is to &lt;a href=&quot;http://www.pythondiary.com/packages/bottle.html&quot;&gt;Bottle&lt;/a&gt;'s example code?  If your looking for a little extra in a micro web framework, without all the extras of &lt;a href=&quot;http://www.pythondiary.com/packages/django.html&quot;&gt;Django&lt;/a&gt; or &lt;a href=&quot;http://www.pythondiary.com/packages/web2py.html&quot;&gt;Web2py&lt;/a&gt;, flask may be a good option for you.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;http://www.pythondiary.com/packages/cherrypy.html&quot;&gt;CherryPy&lt;/a&gt;&lt;/h3&gt;
&lt;a href=&quot;http://c286041.r41.cf1.rackcdn.com/blog_image/cherrypy.png&quot;&gt;&lt;img src=&quot;http://c286041.r41.cf1.rackcdn.com/blog_image/cherrypy.png&quot; border=&quot;0&quot; width=&quot;100&quot; height=&quot;100&quot; /&gt;&lt;/a&gt;
&lt;p&gt;Finally we get to &lt;a href=&quot;http://www.pythondiary.com/packages/cherrypy.html&quot;&gt;CherryPy&lt;/a&gt;.  I have heard many great things about this framework and many Python developers seem to favor it.  I have not personally tried it myself, but I do plan on trying it out to see how it differs from other frameworks out there, micro and otherwise.  They say the framework is a minimalistic one, but I still believe that &lt;a href=&quot;http://www.pythondiary.com/packages/bottle.html&quot;&gt;Bottle&lt;/a&gt; is the smallest one around.  It supports similar components to &lt;a href=&quot;http://www.pythondiary.com/packages/django.html&quot;&gt;Django&lt;/a&gt;, such as caching, sessions, static files, and even authorization.  It also appears to run on many platforms including Android.  Here is the example code snippet from their home page:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;cherrypy&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Hello World!&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exposed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;cherrypy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;quickstart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HelloWorld&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It does look fairly simple, but the last statement &lt;b&gt;quickstart&lt;/b&gt; sort of scares me.  This would imply that there are other methods of starting the application, in effect for larger applications, this simple code snippet above may not be the real deal.  I will look into this one further and see how complex web applications are built and how it would differ from other micro frameworks listed here.&lt;/p&gt;
&lt;h2&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;Now that this entry is coming to a close, I would like to express my final thoughts on so-called micro frameworks.  Are all of these micro frameworks truly needed?  Does having this many cause fragmentation in how Python web development should be done?  Does it cause developer confusion, on which one a developer should learn or avoid?  Let me know what you think about this micro-framework situation us Python developers are faced with in the comments below.&lt;/p&gt;</description>
	<pubDate>Tue, 14 Feb 2012 18:41:00 +0000</pubDate>
</item>
<item>
	<title>PyCon: PyCon 2012: New Relic, Loggly and Skullcandy party!</title>
	<guid>http://pycon.blogspot.com/2012/02/pycon-2012-new-relic-loggly-and.html</guid>
	<link>http://pycon.blogspot.com/2012/02/pycon-2012-new-relic-loggly-and.html</link>
	<description>&lt;p&gt;One of the things we love about our sponsors is their willingness to not just &lt;strong&gt;sponsor &lt;/strong&gt;PyCon - but to get involved, help volunteer, and well - help throw parties!&lt;/p&gt;&lt;p&gt;The first party is courtesy of &lt;a href=&quot;http://newrelic.com/&quot;&gt;New Relic&lt;/a&gt;, &lt;a href=&quot;http://loggly.com/&quot;&gt;Loggly&lt;/a&gt; and &lt;a href=&quot;http://www.skullcandy.com/&quot;&gt;Skullcandy&lt;/a&gt; - from their event page:&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;PyCon 2012 Attendees! Join New Relic, Loggly and Skullcandy for a special PyCon party event on March 9, from 7 pm - 9 pm at the Hyatt Regency Santa Clara (Across from the Convention Center).&lt;/p&gt;&lt;p&gt;Don't miss this opportunity to network with your Python Community peers over drinks and hors d'oeuvres.&lt;/p&gt;&lt;p&gt;Even better, bring your biz card and enter to win some sweet shwag from Skullcandy, maker of premier headphones, earbuds, and headsets. Best of all, it's free! Space is limited to 250 so be sure to register and reserve your spot today!&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;You can sign up for the party right over &lt;a href=&quot;http://www.eventbrite.com/event/2954754751/estw&quot;&gt;here on their events page&lt;/a&gt; - but you'd better hurry, spots are going &lt;em&gt;fast&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;Be warned… It's the night before the PyCon 5k, which starts at 7am sharp the next day :)&lt;/p&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&quot;1&quot; height=&quot;1&quot; src=&quot;https://blogger.googleusercontent.com/tracker/11638628-4540621240446165814?l=pycon.blogspot.com&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;</description>
	<pubDate>Tue, 14 Feb 2012 14:47:59 +0000</pubDate>
</item>
<item>
	<title>Kristján Valur: Clearing weakrefs</title>
	<guid>http://blog.ccpgames.com/kristjan/2012/02/14/clearing-weakrefs/</guid>
	<link>http://blog.ccpgames.com/kristjan/2012/02/14/clearing-weakrefs/</link>
	<description>&lt;p&gt;I just had this problem which would have been elegantly solved with the ability to manually clear weak references pointing to an object.  I am (for technical reasons) recycling an object, so instead of killing it and re-creating it, I re-initialize it.  But that leaves old weak references in place.  How nice wouldn&amp;#8217;t it be to be able to call &amp;#8220;myobject.clear_weakrefs()&amp;#8221;?&lt;/p&gt;</description>
	<pubDate>Tue, 14 Feb 2012 14:17:09 +0000</pubDate>
</item>
<item>
	<title>Rob Galanakis: Large initializers/ctors?</title>
	<guid>http://www.robg3d.com/?p=847</guid>
	<link>http://www.robg3d.com/?p=847</link>
	<description>&lt;p&gt;With closures (and to some extent with runtime attribute assignments), I find the signatures of my UI types shrink and shrink. A lot of times we have code like this (python, but the same would apply to C#):&lt;/p&gt;
&lt;pre&gt;class FooControl(Control):
  def __init__(self, value):
    super(FooControl).__init__()
    self.value = value
    self._InitButtons()    

  def _InitButtons(self):
    self.button = Button('Press Me!', parent=self)
    btn.clicked.addListener(self._OnButtonClick)

  def _OnButtonClick(self):
    print id(self.button), self.value&lt;/pre&gt;
&lt;p&gt;However we can easily rewrite this like so:&lt;/p&gt;
&lt;pre&gt;class FooControl(Control):
  def __init__(self, value):
    super(FooControl).__init__()
    btn = Button('Press Me!', parent=self)
    def onClick():
      print value
    btn.clicked.addListener(onClick)&lt;/pre&gt;
&lt;p&gt;Now this is a trivial example. But I find that many types, UI types in particular, can have most or all of these callback methods (like self._OnButtonClick) removed by turning them into inner functions. And then as you turn them into inner functions in init, you can get rid of stored state (self.value and self.button).&lt;/p&gt;
&lt;p&gt;But as we take this to the extreme, we end up with very simple classes (and in fact I could replace FooControl with a function, it doesn&amp;#8217;t need to be a class at all), but very long init methods (imagine doing all your sub-control creation, layout, AND all callback functionality, inside of one method!).&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve decided I&amp;#8217;d rather have a long init method, usually broken up into several inner functions, rather than a larger signature on the class with layout, callbacks, and stored state. In my mind, it is easier to pull something out into a type attribute, rather than remove it, as anything on the type is liable to be used externally. And breaking up your layout into instance methods that can really only be called once (_InitButtons), from the init, adds a cognitive burden for me.&lt;/p&gt;
&lt;p&gt;So I can justify this decision to eliminate extra attributes rationally, but what seals the deal is, I&amp;#8217;m not unit testing any of this code anyway. So whether it is in one long method, or broken up into several methods, it isn&amp;#8217;t getting tested.&lt;/p&gt;
&lt;p&gt;I started out as very much in the &amp;#8216;break into small methods&amp;#8217; camp but have wholesale moved into the &amp;#8216;one giant __init__ with inner functions&amp;#8217; camp. I&amp;#8217;m curious what you all prefer and why?&lt;/p&gt;</description>
	<pubDate>Tue, 14 Feb 2012 12:03:53 +0000</pubDate>
</item>
<item>
	<title>PyCon: Need dinner plans? Yelp can help!</title>
	<guid>http://pycon.blogspot.com/2012/02/need-dinner-plans-yelp-can-help.html</guid>
	<link>http://pycon.blogspot.com/2012/02/need-dinner-plans-yelp-can-help.html</link>
	<description>&lt;p&gt;&lt;br /&gt; &lt;span&gt;Through all of the &lt;a href=&quot;https://us.pycon.org/2012/schedule/&quot;&gt;talks, tutorials, open spaces and more&lt;/a&gt;, some of the best parts of PyCon are the meals. Especially dinner! Each PyCon ticket gets you catered breakfast and lunch at the conference center, with lunch being a great way to refuel and sit down at a table and meet your next project contributor, business partner, or friend. Dinner, however, is a meal you’re on your own for. Not to worry, because with 1500+ people needing to head out for dinner, there’s never a shortage of groups on the way out for a burger, pasta, falafel, beer, wine, you name it. Some people even use PyCon sponsor &lt;a href=&quot;http://www.yelp.com/&quot;&gt;Yelp.com&lt;/a&gt; to find their dinner destination.&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; &lt;span&gt;This year Yelp has stepped up as a sponsor for food! Not only will they help you find a destination, they’ll be giving rides to a few of the area’s highly rated restaurants. On Friday and Saturday night, Yelp will be renting several buses and driving conference goers to these select eateries, giving you a chance to get out and have a good meal with good company. The details are still being ironed out, but it looks like there will be around five buses each holding approximately 30 people. Yelp plans to send along one of their developers on each bus as an ambassador, and they might bring some nice swag as well!&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt; &lt;span&gt;As for getting on the bus, sign ups will be announced on site on the first day of the conference. You like what you see? Sign up and enjoy! Be sure to sign up on site - first come, first served.&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt; &lt;span&gt;Schedule-wise we’re looking at departure around a half hour after the day’s lightning talks are over, so about 6:30-7:00. We’ll certainly announce a more accurate time during each day’s morning session. Once you’re there, you’ll have 2-2.5 hours to spend at the restaurant and in the area. After that, the bus heads back to the hotel where you can join back up with the festivities. You’ll be back just in time for the evening’s open spaces and &lt;a href=&quot;http://en.wikipedia.org/wiki/Birds_of_a_feather_(computing)&quot;&gt;BoF&lt;/a&gt; sessions!&lt;/span&gt;&lt;br /&gt; &lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt; &lt;span&gt;Bon Appétit!&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&quot;1&quot; height=&quot;1&quot; src=&quot;https://blogger.googleusercontent.com/tracker/11638628-2233087324125218031?l=pycon.blogspot.com&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;</description>
	<pubDate>Tue, 14 Feb 2012 10:20:44 +0000</pubDate>
</item>
<item>
	<title>Shannon -jj Behrens: Python Concurrency Spreadsheet</title>
	<guid>http://jjinux.blogspot.com/2012/02/python-concurrency-spreadsheet.html</guid>
	<link>http://jjinux.blogspot.com/2012/02/python-concurrency-spreadsheet.html</link>
	<description>I'm a fan of Nicholas Piël's &lt;a href=&quot;http://nichol.as/asynchronous-servers-in-python&quot;&gt;Asynchronous Servers in Python&lt;/a&gt; blog post.  In a similar vein, my buddy Shailen Tuli and I put together &lt;a href=&quot;https://docs.google.com/spreadsheet/ccc?key=0AvZ56A18VRlxdDdyOE1kUWFuZXlWenJyUFNKZExUX1E&quot;&gt;the following spreadsheet&lt;/a&gt;.  Feel free to view it on Google Docs and make corrections.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A few notes:&lt;br /&gt;&lt;br /&gt;It is not my goal to use this spreadsheet to pick favorites.  Rather, I'm trying to use this spreadsheet to point out differences among the different approaches.&lt;br /&gt;&lt;br /&gt;I know very little about DieselWeb, MultiTask, FriendlyFlow, Weightless, Fibra, and Cogen.  All I know is that Nicholas Piël's pointed them out as generator-based libraries.&lt;br /&gt;&lt;br /&gt;Some of these libraries support multiple approaches at the same time.  For instance, Twisted lets you use a mix of callbacks, generators, and threads.  Similarly, Tornado lets you use a mix of callbacks and threads.  However, it's important to point out the compromises involved.  For instance, if you're using Tornado, you can't have 5000 concurrent clients to a WSGI server; instead you have to switch over to the asynchronous callback API.&lt;br /&gt;&lt;br /&gt;When I say things like &quot;Can handle 5000 clients?&quot;, I don't mean that each of those requests is actively being served.  There's only so much CPU to go around!  Rather, I mean you can have 5000 clients that are each in various stages of completion, and the server as a whole is mostly waiting on IO.&lt;br /&gt;&lt;br /&gt;You can also read my other blog posts &lt;a href=&quot;http://jjinux.blogspot.com/2009/12/python-concurrency.html&quot;&gt;Python: Concurrency&lt;/a&gt; and &lt;a href=&quot;http://jjinux.blogspot.com/2009/12/python-asynchronous-networking-apis-and.html&quot;&gt;Python: Asynchronous Networking APIs and MySQL&lt;/a&gt;.&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&quot;1&quot; height=&quot;1&quot; src=&quot;https://blogger.googleusercontent.com/tracker/11788780-5183946199365083803?l=jjinux.blogspot.com&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;</description>
	<pubDate>Tue, 14 Feb 2012 10:05:54 +0000</pubDate>
</item>
<item>
	<title>PyCon: PyCon 2012: Want some business cards for PyCon 2012?</title>
	<guid>http://pycon.blogspot.com/2012/02/pycon-2012-want-some-business-cards-for.html</guid>
	<link>http://pycon.blogspot.com/2012/02/pycon-2012-want-some-business-cards-for.html</link>
	<description>&lt;p&gt;The deals and partnerships for PyCon 2012 keep rolling in!&lt;/p&gt;&lt;p&gt;The folks at custom print shop &lt;a href=&quot;http://us.moo.com/&quot;&gt;MOO&lt;/a&gt; are quite good at the printing business, and they’re also good at spotting trends. One they recently noticed was an uptick in business cards intended for PyCon, so they contacted us. With the conference being such a great place to network, from the hallways to the dinner tables, we were able to partner up with them and get you 50 free business cards of your own choosing.&lt;/p&gt;&lt;p&gt;The London-based business card, postcard, and sticker printer will even package up the shipment and deliver straight to Santa Clara, where you can pick up your cards at the registration desk! Talk about easy. All they require is that you pay a small shipping and handling charge and the cards are all yours. If you prefer, they can be mailed to you instead.&lt;/p&gt;&lt;p&gt;If you want to take advantage of this great offer, &lt;a href=&quot;http://moo.com/link/h86f&quot;&gt;http://moo.com/link/h86f&lt;/a&gt; is the PyCon special page. From there you can fill out one of their templates or upload your own design. They even have a product available called Printfinity where you can have many different designs in a pack - 50 different ones if you choose!&lt;/p&gt;&lt;p&gt;Your fancy new cards will come in handy at this year’s new Job Fair. Mingle around with some of PyCon’s 122 sponsors and pass out your details in style.&lt;/p&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&quot;1&quot; height=&quot;1&quot; src=&quot;https://blogger.googleusercontent.com/tracker/11638628-4974815496512925356?l=pycon.blogspot.com&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;</description>
	<pubDate>Tue, 14 Feb 2012 09:52:33 +0000</pubDate>
</item>
<item>
	<title>Maciej Fijalkowsk: PyPy and it's future challenges</title>
	<guid>http://lostinjit.blogspot.com/2012/02/pypy-and-its-future-challenges.html</guid>
	<link>http://lostinjit.blogspot.com/2012/02/pypy-and-its-future-challenges.html</link>
	<description>&lt;p&gt;Obviously I'm biased, but I think PyPy is progressing fairly well. However,&lt;br /&gt;I would like to mention some areas where I think pypy is lagging ---&lt;br /&gt;not living up to its promises or the design decisions simply didn't&lt;br /&gt;turn out as good as we hoped for them. In a fairly arbitrary order:&lt;/p&gt;&lt;br /&gt;&lt;ul class=&quot;simple&quot;&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Whole program type inference&lt;/strong&gt;. This decision has been haunting&lt;br /&gt;separate compilation effort for a while. It's also one of the reasons&lt;br /&gt;why RPython errors are confusing and why the compilation time is so long.&lt;br /&gt;This is less of a concern for users, but more of a concern for developers&lt;br /&gt;and potential developers.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Memory impact&lt;/strong&gt;. We never scientifically measured&lt;br /&gt;memory impact of PyPy on examples. There are reports of outrageous pypy&lt;br /&gt;memory usage, but they're usually very cryptic &amp;quot;my app uses 300M&amp;quot; and not&lt;br /&gt;really reported in a way that's reproducible for us. We simply have to start&lt;br /&gt;measuring memory impact on benchmarks. You can definitely help by providing&lt;br /&gt;us with reproducible examples (they don't have to be small, but they have&lt;br /&gt;to be open source).&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;The next group all are connected. The fundamental question is: What to do&lt;br /&gt;in the situation where the JIT does not help?  There are many causes, but,&lt;br /&gt;in general, PyPy often is inferior to CPython for all of the examples.&lt;br /&gt;A representative, difficult exammple is running tests. Ideally, for&lt;br /&gt;perfect unit tests, each piece of code should be executed only once. There&lt;br /&gt;are other examples, like short running scripts. It all can&lt;br /&gt;be addressed by one or more of the following:&lt;/p&gt;&lt;br /&gt;&lt;ul class=&quot;simple&quot;&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Slow runtime&lt;/strong&gt;. Our runtime is slow. This is caused by a combination&lt;br /&gt;of using a higher&lt;br /&gt;level language than C and a relative immaturity compared to CPython. The&lt;br /&gt;former is at least partly a GCC problem. We emit code that does not look&lt;br /&gt;like hand-written C and GCC is doing worse job at optimizing it. A good&lt;br /&gt;example is operations on longs, which are about 2x slower than CPython's,&lt;br /&gt;partly because GCC is unable to effectively optimize code generated&lt;br /&gt;by PyPy's translator.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Too large JIT warmup time&lt;/strong&gt;. This is again a combination of issues.&lt;br /&gt;Partly this is one of the design decisions of tracing on the metalevel,&lt;br /&gt;which takes more time, but partly this is an issue with our current&lt;br /&gt;implementation that can be addressed. It's also true that in some edge&lt;br /&gt;cases, like running large and complex programs with lots and lots&lt;br /&gt;of megamorphic call sites, we don't do a very good job tracing. Because&lt;br /&gt;a good example of this case is running PyPy's own test suite, I expect&lt;br /&gt;we will invest some work into this eventually.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Slow interpreter&lt;/strong&gt;. This one is very similar to the slow runtime - it's&lt;br /&gt;a combination of using RPython and the fact that we did not spend much&lt;br /&gt;time optimizing it. Unlike the runtime, we might solve it by having an&lt;br /&gt;unoptimizing JIT or some other medium-level solution that would work good&lt;br /&gt;enough. There were some efforts invested, but, as usual, we lack enough&lt;br /&gt;manpower to proceed as rapidly as we would like.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;Thanks for bearing with me this far. This blog post was partly influenced&lt;br /&gt;by accusations that we're doing dishonest PR that PyPy is always fast. I don't&lt;br /&gt;think this is the case and I hope I clarified some of the weak spots, both here&lt;br /&gt;and on the &lt;a class=&quot;reference external&quot; href=&quot;http://pypy.org/performance.html&quot;&gt;performance page&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;b&gt;EDIT:&lt;/b&gt;For what is worth I don't mention interfacing with C here and that's not because I think it's not relevant, it's simply because it did not quite fit with other stuff in this blog post. Consider the list non-exhaustive&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Cheers,&lt;br /&gt;&lt;br /&gt;fijal&lt;/p&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&quot;1&quot; height=&quot;1&quot; src=&quot;https://blogger.googleusercontent.com/tracker/5761095693213568868-7931050948788461510?l=lostinjit.blogspot.com&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;</description>
	<pubDate>Tue, 14 Feb 2012 09:43:51 +0000</pubDate>
</item>
<item>
	<title>Python Diary: First steps into Kivy</title>
	<guid>http://www.pythondiary.com/blog/Feb.13,2012/first-steps-kivy.html</guid>
	<link>http://www.pythondiary.com/blog/Feb.13,2012/first-steps-kivy.html</link>
	<description>&lt;p&gt;I just finished the &lt;a href=&quot;http://www.pythondiary.com/packages/kivy.html&quot;&gt;Kivy&lt;/a&gt; tutorial on how to build a simple &lt;a href=&quot;http://www.pythondiary.com/bookmarks/kivy-pong-game-tutorial&quot;&gt;Pong Game&lt;/a&gt;.  I must say, Kivy is a very interesting framework, and I plan on building some Android apps using it soon.&lt;/p&gt;
&lt;p&gt;The framework makes heavy use of classes to describe each component of your application, and also has a simple language for rapidly building interfaces and binding them in Python.  It has native support for multi-touch screens, which makes it an ideal platform to learn.&lt;/p&gt;
&lt;p&gt;Tablets and smartphones are rather huge right now, and I don't see them going away anytime soon.  Most users of a tablet or smartphone prefer an app over a website, I know I do.  Kivy makes it relatively easy to create an app which is network connected, as it has native support for JSON calls, it manages the web request and decoding of the JSON object for you.&lt;/p&gt;
&lt;p&gt;A small project I plan to implement using Kivy is a simple map viewer for the OHRRPGCE engine.  I have previously created a full map editor in another language and understand the underlying file formats.  I am curious how creating such an application in Kivy will fair.  From what I have read in the documentations for Kivy, I will need to use a texture to map each map tileset onto.  From these map tilesets, I would then blit the required tiles to a new texture for the actual map layers.  I will use touch controls for panning the map around, similar to how Google maps works on a tablet.  I hope to add features such as pinch to zoom and such, since Kivy does support scaling in OpenGL.  I will explain the process throughout this blog for those who are interested in Kivy app development.&lt;/p&gt;
&lt;p&gt;Another interesting project would be to create a Kivy app for this here blog, that way Android users can easily access this blog directly on their device using a nice user interface.&lt;/p&gt;</description>
	<pubDate>Tue, 14 Feb 2012 09:40:01 +0000</pubDate>
</item>
<item>
	<title>Yaniv Aknin: nginx+gzip module might silently corrupt data upon backend failure</title>
	<guid>http://tech.blog.aknin.name/2011/11/04/nginxgzip-module-might-silently-corrupt-data-upon-backend-failure/</guid>
	<link>http://tech.blog.aknin.name/2011/11/04/nginxgzip-module-might-silently-corrupt-data-upon-backend-failure/</link>
	<description>&lt;p&gt;There are several elements that make absolutely certain the page you&amp;#8217;re reading in your browser right now is actually an accurate representation of the resource the HTTP server holds in the URL you requested&lt;sup&gt;1&lt;/sup&gt;. Disregarding caching for a minute, we have two elements making sure the representation you get is protected from errors. The first protecting element is, of course, TCP, making sure that if the server wrote two-hundred bytes in a particular order, either they&amp;#8217;ll all arrive to your end, in order and without errors, or your TCP stack will realize something bad happen and give your user-agent (your browser) a chance to cope with the error. The need for the second protecting element is a bit more sneaky: TCP will guarantee everything the server &lt;em&gt;wrote&lt;/em&gt; will arrive, i.e., bytes for which the server called &lt;tt&gt;write(2)&lt;/tt&gt; or equivalent will arrive, or you&amp;#8217;ll know something went wrong. But what about bytes the server &lt;em&gt;should&lt;/em&gt; have written but didn&amp;#8217;t write all &amp;#8211; for example, because some component on the server&amp;#8217;s side failed?&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://www.w3.org/Protocols/HTTP/AsImplemented.html&quot;&gt;original&lt;/a&gt; HTTP (HTTP 0.9, 1996 time) didn&amp;#8217;t cope with this situation at all. The signal to the client that the server finished talking was to disconnect the TCP session, which, from the client&amp;#8217;s side, is a vague signal. Did the TCP server disconnect because it finished or because it ran into trouble (software fault, sysadmin action, kernel behaviour due to memory pressure or even a bug, etc)? Thankfully, current HTTP kicks in to complement TCP, allowing the server to do one of several things in order to make sure you&amp;#8217;ll at least know you didn&amp;#8217;t receive the whole picture. By far the two most common thing the server will do are to specify a &lt;tt&gt;Content-Length&lt;/tt&gt; in the response&amp;#8217;s header or to use a &lt;tt&gt;Transfer-Encoding&lt;/tt&gt;, most probably &lt;tt&gt;chunked&lt;/tt&gt; transfer encoding.&lt;/p&gt;
&lt;p&gt;Content length is simple to grasp. The server wishes to say 200 bytes. It explicitly says: &amp;#8220;I will say 200 bytes&amp;#8221; in the response header. If the user-agent didn&amp;#8217;t receive 200 bytes of response, it knows something went wrong. Chunked transfer encoding is only slightly more complex &amp;#8211; the server will send the response in chunks, each chunks prefixed by the length of the chunk. The end of the document is marked by a zero-length chunk. So if the user-agent saw a chunk cut in the middle, or didn&amp;#8217;t receive a zero-length chunk, it also knows something went wrong and has a chance to decide what to do about it. For example, when faced with incorrect content length, Chrome displays an &lt;tt&gt;ERR_CONNECTION_CLOSED&lt;/tt&gt; error, whereas Firefox would display the portion of the page it did receive. Different behaviour, yes, but at least both user-agents in this example had a chance realize the response they received is partial. Which is really, really important, you know why? I&amp;#8217;ll tell you why.&lt;/p&gt;
&lt;p&gt;Enter caching. HTTP caching is a non-trivial matter with many unexpected gotchas and pitfalls, and I can&amp;#8217;t cover it all here (why the complexity? I think it&amp;#8217;s because &lt;em&gt;all caching&lt;/em&gt; is an intentional form of &lt;a href=&quot;http://en.wikipedia.org/wiki/Don%27t_Repeat_Yourself&quot;&gt;data/state repetition&lt;/a&gt;, and repetition is something that in my experience humans often have difficulty reasoning about). By far the best document I know about HTTP caching is &lt;a href=&quot;http://www.mnot.net/cache_docs/&quot;&gt;this&lt;/a&gt; splendid guide, but if you&amp;#8217;re in a hurry or impatient, let me summarize the points interesting for this particular post. First, caches might exist in many places, some of them might be surprising, some of them might be slightly broken or at least very aggressive (ISP transparent caches, mutter mutter cough cough). Second, among many other things, HTTP caching lets a server give a client a token together resource, telling the client &amp;#8220;next time you request this resource, tell me you have this token; maybe I&amp;#8217;ll just tell you that the representation you got with this token is still fresh, without transferring it all over again&amp;#8221;. This is called an &lt;tt&gt;ETag&lt;/tt&gt;, and the response that says &amp;#8220;just use what you have in your cache&amp;#8221; is called HTTP &lt;tt&gt;304 NOT MODIFIED&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;How is this relevant to HTTP responses cut in the middle? Well, if servers didn&amp;#8217;t have a way of telling the user-agent how long is the document, and if the response was cut in the middle due to a server fault as described above, the user-agent/sneaky-caching-proxy might cache incorrect responses. If the server also sends an &lt;tt&gt;ETag&lt;/tt&gt; along with the response, the caching entity will store this &lt;tt&gt;ETag&lt;/tt&gt; along with the invalid cached representation, and even when it&amp;#8217;s time to check the representation&amp;#8217;s freshness with the origin server, the server will just take a look at the &lt;tt&gt;ETag&lt;/tt&gt;, say &amp;#8220;yep, this is fine&amp;#8221;, tell the cache to keep using the bad representation and &amp;lt;sinister&amp;gt;never ever let it recover&amp;lt;/sinister&amp;gt;. If this happens on a large ISP&amp;#8217;s transparent cache, easily tens of thousand of your users could be affected. If the affected resource is a common element in many of your pages with strict syntax checking, like a javascript resource, you&amp;#8217;re kinda screwed. The only hope in such a condition is that the client, for some reason, will specify &lt;tt&gt;Cache-Control: no-cache&lt;/tt&gt; in the request, and that caching entities along the path to the server will honour this request. Browsers like caching, so they won&amp;#8217;t usually request &lt;tt&gt;no-cache&lt;/tt&gt;, although AFAIK, recently Chrome started sending &lt;tt&gt;no-cache&lt;/tt&gt; when the user explicitly requests a force-reload (Cmd-R on a Mac). Other browsers don&amp;#8217;t fare as well, and I think that hoping one of your Chrome users will force reload the bad resource in time to save the day is hardly a sturdy solution.&lt;/p&gt;
&lt;p&gt;Bottom line is, it&amp;#8217;s really important to know when a representation of a resource is broken. Which is why I was quite amazed to learn that my HTTP server of choice, nginx, doesn&amp;#8217;t validate the &lt;tt&gt;Content-Length&lt;/tt&gt; it receives from its upstreams and is simply unaware when the response it received from an upstream server is chopped off. If your response specifies a content length but closes the connection without delivering enough bytes, nginx will simply stall the request for a long time without closing the connection downstream, even though it has no hope of receiving additional data to push downstream. I tried this both with &lt;tt&gt;proxy_pass&lt;/tt&gt; and &lt;tt&gt;uwsgi_pass&lt;/tt&gt;, but I&amp;#8217;m quite confident it&amp;#8217;s true for other backends (&lt;tt&gt;fastcgi_pass&lt;/tt&gt;, &lt;tt&gt;scgi_pass&lt;/tt&gt;, etc). This is bad, but not as bad as the case where you want an nginx module to manipulate your content, removing existing content length/transfer encoding and applying its own (the &lt;a href=&quot;http://wiki.nginx.org/HttpGzipModule#gzip_http_version&quot;&gt;gzip&lt;/a&gt; module indeed does that). If a backend error occurs while content-length-oblivious-nginx is altering the data, the content altering module will apply what it applies to the bytes it received, &lt;em&gt;add new content-length/transfer-encoding, assuring everyone the response is OK&lt;/em&gt;, and entice user-agents or even proxies to enter the almost-never-recover bad cache scenario I described in the previews paragraph. Ouch!&lt;/p&gt;
&lt;p&gt;The proper way to fix this, IMHO, is that nginx simply must start looking at the upstream&amp;#8217;s content length (or transfer encoding, once nginx starts using chunked responses with its upstreams). Part of the reason I&amp;#8217;m writing this post is that Maxim Dounin, venerable nginx comitter and an OK chap overall, &lt;a href=&quot;http://forum.nginx.org/read.php?2,216085,216094#msg-216094&quot;&gt;told me&lt;/a&gt; he doesn&amp;#8217;t consider this a top priority at the moment, but I humbly disagree with his assessment of how serious the issue is. Until such a time as nginx is fixed about this, I think you must disable all content-manipulating nginx modules and instead handle all message length affecting work in your upstream (compression, addition, etc). This is what I opted to do with my django based web app, I replaced nginx&amp;#8217;s gzip module with Django&amp;#8217;s &lt;tt&gt;&lt;a href=&quot;https://docs.djangoproject.com/en/dev/ref/middleware/#module-django.middleware.gzip&quot;&gt;GZipMiddleware&lt;/a&gt;&lt;/tt&gt;. It&amp;#8217;s a terrible shame though. It&amp;#8217;s doing the job of nginx for it, probably in a lesser fashion than how nginx could, it &lt;a href=&quot;http://www.python.org/dev/peps/pep-0333/#handling-the-content-length-header&quot;&gt;violates&lt;/a&gt; a &lt;b&gt;must not&lt;/b&gt; clause in Python&amp;#8217;s WSGI PEP333, and I have empiric proof that Tim Berners-Lee chokes a kitten every time you do it.&lt;/p&gt;
&lt;p&gt;But what&amp;#8217;s the alternative? Risk invisibly cached corrupt data for an undetermined length of time? Ditch nginx, which I think is the best HTTP server on this planet despite this debacle? Nah. Both are unacceptable.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;span class=&quot;footer&quot;&gt;&lt;sup&gt;1&lt;/sup&gt; This post assumes convenient values of &amp;#8220;absolutely certain&amp;#8221;; also, everything related to security/content tampering is out of scope in this post. I&amp;#8217;m talking about possibly misbehaving but certainly well-meaning components.&lt;/span&gt;&lt;/p&gt;
&lt;br /&gt; Tagged: &lt;a href=&quot;http://tech.blog.aknin.name/tag/django/&quot;&gt;django&lt;/a&gt;, &lt;a href=&quot;http://tech.blog.aknin.name/tag/http/&quot;&gt;http&lt;/a&gt;, &lt;a href=&quot;http://tech.blog.aknin.name/tag/nginx/&quot;&gt;nginx&lt;/a&gt;, &lt;a href=&quot;http://tech.blog.aknin.name/tag/python/&quot;&gt;python&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gocomments/niltowrite.wordpress.com/1131/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/niltowrite.wordpress.com/1131/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/godelicious/niltowrite.wordpress.com/1131/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/delicious/niltowrite.wordpress.com/1131/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gofacebook/niltowrite.wordpress.com/1131/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/facebook/niltowrite.wordpress.com/1131/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gotwitter/niltowrite.wordpress.com/1131/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/twitter/niltowrite.wordpress.com/1131/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gostumble/niltowrite.wordpress.com/1131/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/stumble/niltowrite.wordpress.com/1131/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/godigg/niltowrite.wordpress.com/1131/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/digg/niltowrite.wordpress.com/1131/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/goreddit/niltowrite.wordpress.com/1131/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/reddit/niltowrite.wordpress.com/1131/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://stats.wordpress.com/b.gif?host=tech.blog.aknin.name&amp;blog=12830832&amp;post=1131&amp;subd=niltowrite&amp;ref=&amp;feed=1&quot; width=&quot;1&quot; height=&quot;1&quot; /&gt;</description>
	<pubDate>Tue, 14 Feb 2012 09:07:01 +0000</pubDate>
</item>
<item>
	<title>Catherine Devlin: Growth in PyCon sponsorship</title>
	<guid>http://catherinedevlin.blogspot.com/2012/02/growth-in-pycon-sponsorship.html</guid>
	<link>http://catherinedevlin.blogspot.com/2012/02/growth-in-pycon-sponsorship.html</link>
	<description>When I teach Python, I usually include a slide or two about Python's importance and growth.  At this point, that's begun to feel unnecessary - but I think I will include this illustration, because it's a neat one.&lt;br /&gt;&lt;br /&gt;In 2004, I'd just started looking at Python.  When I found out that PyCon would be just a few miles from my sister-in-law's house, I thought, &quot;Why not?&quot; - and I fell in love with the Python community forever.  PyCon 2004 had nine sponsors.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-&lt;br /&gt;EaIcazSWNM0/TzqSGPSnAPI/AAAAAAAAAJM/DDursOJS8PU/s1600/pycon2004sponsors.png&quot;&gt;&lt;br /&gt;EaIcazSWNM0/TzqSGPSnAPI/AAAAAAAAAJM/DDursOJS8PU/s1600/pycon2004sponsors.png&quot;&gt;&lt;br /&gt;EaIcazSWNM0/TzqSGPSnAPI/AAAAAAAAAJM/DDursOJS8PU/s1600/pycon2004sponsors.png&quot;&gt;&lt;br /&gt;EaIcazSWNM0/TzqSGPSnAPI/AAAAAAAAAJM/DDursOJS8PU/s1600/pycon2004sponsors.png&quot;&gt;&lt;img src=&quot;http://4.bp.blogspot.com/-EaIcazSWNM0/TzqSGPSnAPI/AAAAAAAAAJM/DDursOJS8PU/s320/pycon2004sponsors.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5709036113526980850&quot; /&gt;&lt;/a&gt;&lt;br /&gt;This year, I barely squeaked my registration in before the blast doors slammed shut.  Here are PyCon US 2012's sponsors.&lt;br /&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-FOdi-zkwxWE/TzqSNXOu_UI/AAAAAAAAAJY/2K0P4jAvvPE/s1600/pycon2012sponsors.png&quot;&gt;&lt;img src=&quot;http://4.bp.blogspot.com/-FOdi-zkwxWE/TzqSNXOu_UI/AAAAAAAAAJY/2K0P4jAvvPE/s320/pycon2012sponsors.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5709036235917294914&quot; /&gt;&lt;/a&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&quot;1&quot; height=&quot;1&quot; src=&quot;https://blogger.googleusercontent.com/tracker/11802292-7490768865468269441?l=catherinedevlin.blogspot.com&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;</description>
	<pubDate>Tue, 14 Feb 2012 08:59:12 +0000</pubDate>
</item>
<item>
	<title>S. Lott: Multiprocessing Goodness -- Part 2 -- Class Defintions</title>
	<guid>http://slott-softwarearchitect.blogspot.com/2012/02/multiprocessing-goodness-part-2-class.html</guid>
	<link>http://slott-softwarearchitect.blogspot.com/2012/02/multiprocessing-goodness-part-2-class.html</link>
	<description>The &lt;a href=&quot;http://docs.python.org/library/multiprocessing.html&quot; target=&quot;_blank&quot;&gt;multiprocessing&lt;/a&gt; module includes a generic &lt;a href=&quot;http://docs.python.org/library/multiprocessing.html#multiprocessing.Process&quot; target=&quot;_blank&quot;&gt;Process&lt;/a&gt; class, which can be used to wrap a simple function.&lt;br /&gt;&lt;br /&gt;The function must be designed to work with Queues or Pipelines or other synchronization techniques. &lt;br /&gt;&lt;br /&gt;There's an advantage, however, to defining a class which gracefully handles generator functions. &amp;nbsp;If we have Generator-Aware multi-processing, we can (1) write our algorithms as generators and then (2) trivially connect Processes with Queues to improve scalability. &lt;br /&gt;&lt;br /&gt;We're looking at creating processing &quot;pipelines&quot; using Queues. &amp;nbsp;That way we can easily handle multiple-producer and multiple-consumer (fan-in, fan-out) processing that enhances concurrency. &lt;br /&gt;&lt;br /&gt;See &lt;a href=&quot;http://slott-softwarearchitect.blogspot.com/2012/02/multiprocessing-goodness-part-1-use.html&quot; target=&quot;_blank&quot;&gt;Multiprocessing Goodness -- Part 1 -- Use Cases&lt;/a&gt; for more information.&lt;br /&gt;&lt;br /&gt;We have three use cases: &amp;nbsp;Producer, Consumer and Consumer-Producer.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Producer&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;A Producer gets data from somewhere and populates a queue with it. &amp;nbsp;This is the source that feeds data into the pipeline.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;class ProducerProcess( Process ):&lt;br /&gt;    &quot;&quot;&quot;Produces items into a Queue.&lt;br /&gt;    &lt;br /&gt;    The &quot;target&quot; must be a generator function which yields&lt;br /&gt;    pickable items.&lt;br /&gt;    &quot;&quot;&quot;&lt;br /&gt;    def __init__( self, group=None, target=None, name=None, args=None, kwargs=None, output_queue=None, consumers=0 ):&lt;br /&gt;        super( ProducerProcess, self ).__init__( name=name )&lt;br /&gt;        self.target= target&lt;br /&gt;        self.args= args if args is not None else []&lt;br /&gt;        self.kwargs= kwargs if kwargs is not None else {}&lt;br /&gt;        self.output_queue= output_queue&lt;br /&gt;        self.consumers= consumers&lt;br /&gt;    def run( self ):&lt;br /&gt;        target= self.target&lt;br /&gt;        for item in target(*self.args, **self.kwargs):&lt;br /&gt;            self.output_queue.put( item )&lt;br /&gt;        for x in range(self.consumers):&lt;br /&gt;            self.output_queue.put( None )&lt;br /&gt;        self.output_queue.close()&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This class will wrap a &quot;target&quot; function which &lt;b&gt;must&lt;/b&gt; be a generator. &amp;nbsp; Every value yielded is put into the &quot;output_queue&quot;. &amp;nbsp;When the source data runs out, enough sentinel tokens are put into the queue to satisfy all consumers.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Consumer&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;A Consumer gets data from a queue and does some final processing. &amp;nbsp;Perhaps it loads a database, or writes a file. &amp;nbsp;It is the sink that consumes data on the pipeline.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;class ConsumerProcess( Process ):&lt;br /&gt;    &quot;&quot;&quot;Consumes items from a Queue.&lt;br /&gt;    &lt;br /&gt;    The &quot;target&quot; must be a function which expects an iterable as it's&lt;br /&gt;    only argument.  Therefore, the args value is not used here.&lt;br /&gt;    &quot;&quot;&quot;&lt;br /&gt;    def __init__( self, group=None, target=None, name=None, kwargs=None, input_queue=None, producers=0 ):&lt;br /&gt;        super( ConsumerProcess, self ).__init__( name=name )&lt;br /&gt;        self.target= target&lt;br /&gt;        self.kwargs= kwargs if kwargs is not None else {}&lt;br /&gt;        self.input_queue= input_queue&lt;br /&gt;        self.producers= producers&lt;br /&gt;    def items( self ):&lt;br /&gt;        while self.producers != 0:&lt;br /&gt;            for item in iter( self.input_queue.get, None ):&lt;br /&gt;                yield item&lt;br /&gt;            self.producers -= 1&lt;br /&gt;    def run( self ):&lt;br /&gt;        target= self.target&lt;br /&gt;        target( self.items(), **self.kwargs )&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This class will wrap a &quot;target&quot; function which must be ready to work with any iterable. &amp;nbsp;Every value from the queue will be provided to the target function for processing. &amp;nbsp;When enough sentinel tokens have been consumed from producers, it terminates processing.&lt;br /&gt;&lt;br /&gt;Consumer-Producer&lt;br /&gt;&lt;br /&gt;The middle of a processing pipeline is consumer-producer processes which consume from one queue and the produce to another queue.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;        &lt;br /&gt;class ConsumerProducerProcess( Process ):&lt;br /&gt;    &quot;&quot;&quot;Consumes items from a Queue and produces items onto a Queue.&lt;br /&gt;    &lt;br /&gt;    The &quot;target&quot; must be a generator function which yields&lt;br /&gt;    pickable items and which expects an iterable as it's&lt;br /&gt;    only argument.  Therefore, the args value is not used here.&lt;br /&gt;    &quot;&quot;&quot;&lt;br /&gt;    def __init__( self, group=None, target=None, name=None, kwargs=None, input_queue=None, producers=0, output_queue=None, consumers=0 ):&lt;br /&gt;        super( ConsumerProducerProcess, self ).__init__( name=name )&lt;br /&gt;        self.target= target&lt;br /&gt;        self.kwargs= kwargs if kwargs is not None else {}&lt;br /&gt;        self.input_queue= input_queue&lt;br /&gt;        self.producers= producers&lt;br /&gt;        self.output_queue= output_queue&lt;br /&gt;        self.consumers= consumers&lt;br /&gt;    def items( self ):&lt;br /&gt;        while self.producers != 0:&lt;br /&gt;            for item in iter( self.input_queue.get, None ):&lt;br /&gt;                yield item&lt;br /&gt;            self.producers -= 1&lt;br /&gt;    def run( self ):&lt;br /&gt;        target= self.target&lt;br /&gt;        for item in target(self.items(), **self.kwargs):&lt;br /&gt;            self.output_queue.put( item )&lt;br /&gt;        for x in range(self.consumers):&lt;br /&gt;            self.output_queue.put( None )&lt;br /&gt;        self.output_queue.close()&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This class will wrap a &quot;target&quot; function which must be a generator function that consumes an iterable.&lt;br /&gt;Every value from the queue is provided to the target generator. &amp;nbsp;Every value yielded by the generator is sent to the output queue. &amp;nbsp;The input side counts sentinels to know when to stop. &amp;nbsp;The output side produces enough sentinels to alert downstream processes.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Target Functions&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;A producer function must be a generator function of this form&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;def prod( *args ):&lt;br /&gt;    for item in some_function(*args):&lt;br /&gt;       yield item&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A consumer function looks like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;def cons( source ):&lt;br /&gt;    for item in source:&lt;br /&gt;       final_disposition(item)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally, a consumer-producer function looks like this.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;def cons_prod( source ):&lt;br /&gt;    for item in source:&lt;br /&gt;       next_value= transform(item)&lt;br /&gt;       yield next_value&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;These functions can be tested and debugged like this.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;for final in consumer( cons_prod( producer( *args ) ) ):&lt;br /&gt;    print( final )&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That way we're confident that our algorithm is correct before attempting to scale it with multiprocessing.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&quot;1&quot; height=&quot;1&quot; src=&quot;https://blogger.googleusercontent.com/tracker/684183198890094283-9053507732184669298?l=slott-softwarearchitect.blogspot.com&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;</description>
	<pubDate>Tue, 14 Feb 2012 08:32:13 +0000</pubDate>
</item>
<item>
	<title>S. Lott: TDRE - Test Driven Reverse Engineering Case Study</title>
	<guid>http://slott-softwarearchitect.blogspot.com/2012/02/tdre-test-driven-reverse-engineering.html</guid>
	<link>http://slott-softwarearchitect.blogspot.com/2012/02/tdre-test-driven-reverse-engineering.html</link>
	<description>&lt;b&gt;Background&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Read up on compass variation or declination. &amp;nbsp;For example, this &lt;a href=&quot;http://www.ngdc.noaa.gov/geomag/declination.shtml&quot; target=&quot;_blank&quot;&gt;NOAA&lt;/a&gt; site provides some useful information.&lt;br /&gt;&lt;br /&gt;Mariners use the magnetic variation to compute the difference between True north (i.e., aligned with the grid on the chart) and Magnetic north (i.e., aligned with the compass.) &lt;br /&gt;&lt;br /&gt;The essential use case here is &quot;What's the compass variation at a given point?&quot; &amp;nbsp;The information is printed on paper charts, but it's more useful to simply calculate it.&lt;br /&gt;&lt;br /&gt;There are two &lt;a href=&quot;http://www.ngdc.noaa.gov/geomag/models.shtml&quot; target=&quot;_blank&quot;&gt;magnetic models&lt;/a&gt;: the US Department of Defense World Magnetic Model (WMM) and the&amp;nbsp;International Association of Geomagnetism and Aeronomy&amp;nbsp;(IAGA) &lt;a href=&quot;http://www.ngdc.noaa.gov/IAGA/vmod/igrf.html&quot; target=&quot;_blank&quot;&gt;International Geomagnetic Reference Field (IGRF)&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A packaged solution is geomag7.0. &amp;nbsp;This includes both the WMM and the IGRF models. &amp;nbsp;This is quite complex. &amp;nbsp;However, it does have &quot;sample output&quot;, which amount to unit test cases.&lt;br /&gt;&lt;br /&gt;The essential spherical harmonic model is available separately as a small Fortran program, &lt;a href=&quot;http://www.ngdc.noaa.gov/IAGA/vmod/igrf11.f&quot; target=&quot;_blank&quot;&gt;igrf11.f&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Which leads us to reverse engineering this program into Python.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;TDRE Approach&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The TDRE approach requires having some test cases to drive the reverse engineering process toward some kind of useful results.&lt;br /&gt;&lt;br /&gt;The geomag7.0 package includes two &quot;Sample Output&quot; files that have the relevant unit test cases. &amp;nbsp;The file has column headings and 16 test cases. &amp;nbsp;This leads us to the following outline for the unit test application.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    class Test_Geomag( unittest.TestCase ):&lt;br /&gt;        def __init__( self, row ):&lt;br /&gt;            super( Test_Geomag, self ).__init__()&lt;br /&gt;            self.row= row&lt;br /&gt;        def runTest( self ):&lt;br /&gt;            row= self.row&lt;br /&gt;            if details: &lt;br /&gt;                print( &quot;Source: {0:10s} {1} {2:7s} {3:10s} {4:10s} {5:5s} {6:5s}&quot;.format( row['Date'], row['Coord-System'], row['Altitude'], row['Latitude'], row['Longitude'], row['D_deg'], row['D_min'] ),&lt;br /&gt;                file=details )&lt;br /&gt;            &lt;br /&gt;            date= self.parse_date( row['Date'] )&lt;br /&gt;            lat= self.parse_lat_lon( row['Latitude'] )&lt;br /&gt;            lon= self.parse_lat_lon( row['Longitude'] )&lt;br /&gt;            alt= self.parse_altitude(row['Altitude'] )&lt;br /&gt;            &lt;br /&gt;            x, y, z, f = igrf11syn( date, lat*math.pi/180, lon*math.pi/180, alt, coord=row['Coord-System'] )&lt;br /&gt;            D = 180.0/math.pi*math.atan2(y, x) # Declination &lt;br /&gt;&lt;br /&gt;            deg, min = deg2dm( D )&lt;br /&gt;            &lt;br /&gt;            if details: &lt;br /&gt;                print( &quot;Result: {0:10.5f} {1} K{2:&amp;lt;6.1f} {3:&amp;lt;10.3f} {4:&amp;lt;10.3f} {5:5s} {6:5s}&quot;.format( date, row['Coord-System'], alt, lat, lon, str(deg)+&quot;d&quot;, str(min)+&quot;m&quot; ), &lt;br /&gt;                    file=details )&lt;br /&gt;                print( file=details )&lt;br /&gt;            &lt;br /&gt;            self.assertEqual( row['D_deg'], &quot;{0}d&quot;.format(deg) )&lt;br /&gt;            self.assertEqual( row['D_min'], &quot;{0}m&quot;.format(min) )&lt;br /&gt;&lt;br /&gt;    def suite():&lt;br /&gt;        s= unittest.TestSuite()&lt;br /&gt;        with open(sample_output,&quot;r&quot;) as expected:&lt;br /&gt;            rdr= csv.DictReader( expected, delimiter=' ', skipinitialspace=True )&lt;br /&gt;            for row in rdr:&lt;br /&gt;                case= Test_Geomag( row )&lt;br /&gt;                s.addTest( case )&lt;br /&gt;        return s&lt;br /&gt;&lt;br /&gt;    r = unittest.TextTestRunner(sys.stdout)&lt;br /&gt;    result= r.run( suite() )&lt;br /&gt;    sys.exit(not result.wasSuccessful())&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;span class=&quot;Apple-style-span&quot;&gt;Test_Geomag&lt;/span&gt; class does two things. &amp;nbsp;First, it parses the source values to create a usable test case. &amp;nbsp;We've omitted the parsers to reduce clutter. &amp;nbsp;Second, it produces details to help with debugging. &amp;nbsp;This is reverse engineering, and there's &lt;b&gt;lots&lt;/b&gt;&amp;nbsp;of debugging.&amp;nbsp; It depends on a global variable, &lt;span class=&quot;Apple-style-span&quot;&gt;details&lt;/span&gt;, which is either set to &lt;span class=&quot;Apple-style-span&quot;&gt;sys.stderr&lt;/span&gt; or &lt;span class=&quot;Apple-style-span&quot;&gt;None&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;This &lt;span class=&quot;Apple-style-span&quot;&gt;suite()&lt;/span&gt; function builds a suite of test cases from the input file. &lt;br /&gt;&lt;br /&gt;The unit under test isn't obvious, but there's a call to the&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot;&gt;igrf11syn()&lt;/span&gt;&amp;nbsp;function where the important work gets done. &amp;nbsp;We can start with this.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;def  igrf11syn( date, nlat, elong, alt=0.0, coord='D' ):&lt;br /&gt;    return None, None, None, None&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This lets us run the tests and find that we have work to do.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reverse Engineering&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The IGRF11.F fortran code contains this &lt;span class=&quot;Apple-style-span&quot;&gt;IGRF11SYN&lt;/span&gt; &quot;subroutine&quot; that does the work we want. &amp;nbsp;The geomag 7.0 package has a function called &lt;span class=&quot;Apple-style-span&quot;&gt;shval3&lt;/span&gt; which is essentially the same thing.&lt;br /&gt;&lt;br /&gt;Both are implementations of the same underlying &quot;13th order spherical harmonic series&quot; or a &quot;truncated series expansion&quot;.&lt;br /&gt;&lt;br /&gt;The Fortran code contains numerous Fortran &quot;optimizations&quot;. &amp;nbsp;These are irritating hackarounds because of actual (and perceived) limitations of Fortran. &amp;nbsp;They fall into two broad classes.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Hand Optimizations&lt;/b&gt;. &amp;nbsp;All repeated expressions were manually hoisted out of their context. &amp;nbsp;This is clever but makes the code particularly obscure. &amp;nbsp;It doesn't help when local variables are named &lt;span class=&quot;Apple-style-span&quot;&gt;ONE&lt;/span&gt;, &lt;span class=&quot;Apple-style-span&quot;&gt;TWO&lt;/span&gt; and &lt;span class=&quot;Apple-style-span&quot;&gt;THREE&lt;/span&gt;. &amp;nbsp;Bad is it is, not much needs to be done about this. &amp;nbsp;Python code looks a bit like Fortran code, so very little needs to be done except add `math.` to the various function calls like sort, cos and sin.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Sparse Array Chicanery&lt;/b&gt;. &amp;nbsp;There are actually two spherical harmonic series. &amp;nbsp;The older 10-order and the new 13-order. &amp;nbsp; Each model has two sets of coefficients: &lt;i&gt;g&lt;/i&gt; and &lt;i&gt;h&lt;/i&gt;. &amp;nbsp;These form two half-matrices plus a vector. &amp;nbsp;The old models have 55 &lt;i&gt;g&lt;/i&gt; values in one matrix, 55 &lt;i&gt;h&lt;/i&gt; values in second matrix, and a set of 10 more &lt;i&gt;g&lt;/i&gt; values that form some kind of vector; 160 values. &amp;nbsp;The new models have 91 g, 91 &lt;i&gt;h&lt;/i&gt; and 13 &lt;i&gt;g&lt;/i&gt; in the extra vector; 195 values. &amp;nbsp;There are 23 sets of these coefficients (for 1900, 1905, ... 2015). &amp;nbsp;The &lt;i&gt;worst&lt;/i&gt;&amp;nbsp;case is 23×195=4,485 values. &amp;nbsp;This appears to be too much memory, so the two matrices and vectors are optimized into a single opaque collection of 3,256 numbers and delightfully complex set of index calculations.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;b&gt;Phase 1.&lt;/b&gt; &amp;nbsp;Do the smallest &quot;literal&quot; transformation of Fortran to Python.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This means things like this:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Transforming the subroutine into a Python function with multiple return values.&lt;/li&gt;&lt;li&gt;Reasoning out the overall &quot;steps&quot;. &amp;nbsp;There's a bunch of setup followed by the essential series calculation followed by some final calculations.&lt;/li&gt;&lt;li&gt;Locating and populating the global variables.&lt;/li&gt;&lt;li&gt;Reformatting the &lt;b&gt;if&lt;/b&gt; statements.&lt;/li&gt;&lt;li&gt;Removing the GOTO's. &amp;nbsp;Either make them separate functions or properly nest the code.&lt;/li&gt;&lt;li&gt;Reformatting the &lt;b&gt;do&lt;/b&gt;&amp;nbsp;loop.&lt;/li&gt;&lt;li&gt;Handling the 1-based indexing. &amp;nbsp;In almost all cases, Fortran &quot;arrays&quot; are best handled as Python dictionaries (&lt;b&gt;not&lt;/b&gt; lists). &amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Once this is done, there are some remaining special-case discrepancies. &amp;nbsp;Most of these are tacit assumptions about the problem domain that turn out to be untrue. &amp;nbsp;For example, the Geodetic, Geocentric features seemed needless. &amp;nbsp;However, they're not handled trivially, and need to be left in place. &amp;nbsp;Also, conversion of signed values in radians to degrees and minutes isn't trivial.&amp;nbsp;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This leads to passing all 16 unit tests with the&amp;nbsp;single opaque collection of 3,256 numbers and delightfully complex set of index calculations.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Phase 2.&lt;/b&gt; &amp;nbsp;Optimize so that it makes some sense in Python.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This involves unwinding the index calculations to simplify the array. &amp;nbsp;The raw coefficients are available (&lt;a href=&quot;http://www.ngdc.noaa.gov/IAGA/vmod/igrf11coeffs.txt&quot; target=&quot;_blank&quot;&gt;igrf11coeffs.txt&lt;/a&gt;) and they have a sensible structure that separates the two matrices very cleanly. &amp;nbsp;The code uses the combined matrix (called &lt;span class=&quot;Apple-style-span&quot;&gt;gh&lt;/span&gt;) in a very few places. &amp;nbsp;The index calculations aren't obvious at all, but a few calls to &lt;span class=&quot;Apple-style-span&quot;&gt;print&lt;/span&gt; reveal how the matrix is accessed. &amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Given (1) unit tests that already work and (2) the pattern of access, it's relatively easy to hypothesize a dictionary by year that contains a pair of simple dictionaries, g[n,m] and h[n,m], for the coefficients.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Cleanup and Packaging&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Once the tests pass, the package -- as a whole -- needs to be made reasonably Pythonic. &amp;nbsp; In this case, it means a number of additional changes. &amp;nbsp;For example, converting the API from degrees to radians, supplying appropriate default values for parameters, providing convenience functions.&lt;br /&gt;&lt;br /&gt;Additionally, there are Python ways to populate the coefficients neatly and eliminate global variables. &amp;nbsp;In this case, it seemed sensible to create a Callable class which could load the coefficients during construction.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;Note that there's little point in profiling to apply further optimizations. &amp;nbsp;The legacy Fortran code was already meticulously hand optimized. &amp;nbsp;&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&quot;1&quot; height=&quot;1&quot; src=&quot;https://blogger.googleusercontent.com/tracker/684183198890094283-4554637467799012132?l=slott-softwarearchitect.blogspot.com&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;</description>
	<pubDate>Tue, 14 Feb 2012 08:00:04 +0000</pubDate>
</item>
<item>
	<title>Wallix: Announcing PyLogsParser 0.4</title>
	<guid>http://www.wallix.org/2012/02/14/announcing-pylogsparser-0-4/</guid>
	<link>http://www.wallix.org/2012/02/14/announcing-pylogsparser-0-4/</link>
	<description>Wallix LogBox team is happy to announce version 0.4 of PyLogsParser. New normalizers Wallix AdminBastion authentication logs, written by Nassim Babaci Cisco ASA logs. Dansguardian logs. Features Adds Common Callbacks facility : a library of functions that are ready to &amp;#8230; &lt;a href=&quot;http://www.wallix.org/2012/02/14/announcing-pylogsparser-0-4/&quot;&gt;Continue reading &lt;span class=&quot;meta-nav&quot;&gt;&amp;#8594;&lt;/span&gt;&lt;/a&gt;</description>
	<pubDate>Tue, 14 Feb 2012 07:41:35 +0000</pubDate>
</item>
<item>
	<title>Yuval Greenfield: Python isn&amp;#8217;t English and iterator &amp;#8220;labels&amp;#8221;</title>
	<guid>http://uberpython.wordpress.com/2012/02/13/python-isnt-english-and-iterator-labels/</guid>
	<link>http://uberpython.wordpress.com/2012/02/13/python-isnt-english-and-iterator-labels/</link>
	<description>&lt;p&gt;Us python fanboys like to think of python as similar to English and thus more readable. Let&amp;#8217;s examine a simple piece of code:&lt;/p&gt;
&lt;pre&gt;for item in big_list:
    if item.cost &amp;gt; 5:
        continue
    item.purchase()&lt;/pre&gt;
&lt;p&gt;For our discussion there are only 3 kinds of people:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;People who have never seen a line of code in their life.&lt;/li&gt;
&lt;li&gt;Have programmed in other languages but have never seen python.&lt;/li&gt;
&lt;li&gt;Python programmers.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;We&amp;#8217;ll dabble between the first 2 groups and how they parse the above. Let&amp;#8217;s try to forget what we know about python or programming and read that in English:&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&amp;#8220;for item in big_list&amp;#8221; &amp;#8211; either we&amp;#8217;re talking about doing something for a specific item in a big_list or we&amp;#8217;re talking about every single item. Ambiguous but the first option doesn&amp;#8217;t really make sense so that&amp;#8217;s fine.&lt;/li&gt;
&lt;li&gt;&amp;#8220;if item.cost &amp;gt; 5&amp;#8243; &amp;#8211; non-programmers are going to talk about the period being in a strange place, but programmers will know exactly what&amp;#8217;s up.&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;&amp;#8220;continue&amp;#8221; &amp;#8211; That&amp;#8217;s fine, keep going. English speakers are going to get the completely wrong idea. As programmers we&amp;#8217;ve grown used to this convention though its meaning in English is very specifically equivalent to what pythonistas call &amp;#8220;pass&amp;#8221; or &amp;#8220;nop&amp;#8221; in assembly. We really should have called this &amp;#8220;&lt;strong&gt;skip&lt;/strong&gt;&amp;#8221; or something.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&amp;#8220;item.purchase()&amp;#8221; &amp;#8211; non-programmers are going to ask about the period and the parentheses but the rest grok that easily.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I&amp;#8217;m pretty sure this isn&amp;#8217;t English. But it&amp;#8217;s fairly readable for a programmer. I believe programmers of any of the &lt;a title=&quot;tiobe index&quot; href=&quot;http://www.tiobe.com/content/paperinfo/tpci/index.html&quot;&gt;top 8 languages on the TIOBE index&lt;/a&gt; can understand simple python. I definitely can&amp;#8217;t say the same for Lisp and Haskell. Not that there&amp;#8217;s anything wrong with Lisp/Haskell, these languages have specialized syntax for their honorable reasons.&lt;/p&gt;
&lt;h2&gt;Continue is a silly word, what about iterator labels?&lt;/h2&gt;
&lt;p&gt;Let&amp;#8217;s say I want to break out of an outer loop from a nested loop, eg:&lt;/p&gt;
&lt;pre&gt;for item in big_list:
    for review in item.reviews:
        if review &amp;lt; 3.0:
            # next item or next review?
            continue
        if review &amp;gt; 9.0:
            # stop reading reviews or stop looking for items?
            break&lt;/pre&gt;
&lt;p&gt;Java supports &lt;strong&gt;specific breaks and continues&lt;/strong&gt; by adding labels to the for loops but I think we can do better. How about this:&lt;/p&gt;
&lt;pre&gt;items_gen = (i for i in big_list)
for item in items_gen:
    for review in item.reviews:
        if review &amp;lt; 3.0:
            items_gen.continue()
        if review &amp;gt; 9.0:
            items_gen.break()&lt;/pre&gt;
&lt;p&gt;But how can that even be possible you may ask? Well, nowadays it isn&amp;#8217;t but maybe one day if &lt;a title=&quot;python ideas&quot; href=&quot;http://mail.python.org/mailman/listinfo/python-ideas&quot;&gt;python-ideas&lt;/a&gt; like this idea we can have nice things. Here&amp;#8217;s how I thought it could work: a for-loop on a generator can theoretically look like this:&lt;/p&gt;
&lt;pre&gt;while True:
    try:
        item = next(gen)
        # do stuff with item
    except StopIteration:
        break&lt;/pre&gt;
&lt;p&gt;But if it worked like I propose below we can support the specific breaks and continues:&lt;/p&gt;
&lt;pre&gt;while True:
    try:
        item = next(gen)
        # do stuff with item
    except gen.ContinueIteration:
        pass
    except gen.StopIteration:
        break
    except StopIteration:
        break&lt;/pre&gt;
&lt;p&gt;So every generator could have a method which throws its relevant exception and we could write specific breaks and continues. Or if you prefer a different spelling could be &amp;#8220;break from mygen&amp;#8221; or &amp;#8220;continue from mygen&amp;#8221; as continue and break aren&amp;#8217;t allowed as method names normally.&lt;/p&gt;
&lt;p&gt;I think this could be nice. Although many times I found myself using nested loops I actually preferred to break the monster into 2 functions with one loop each. That way I could use the return value to do whatever I need in the outer loop (break/continue/etc). So perhaps it&amp;#8217;s a good thing the language doesn&amp;#8217;t help me build monstrosity&amp;#8217;s and forces me to flatten my code. I wonder.&lt;/p&gt;
&lt;br /&gt;  &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gocomments/uberpython.wordpress.com/575/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/uberpython.wordpress.com/575/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/godelicious/uberpython.wordpress.com/575/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/delicious/uberpython.wordpress.com/575/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gofacebook/uberpython.wordpress.com/575/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/facebook/uberpython.wordpress.com/575/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gotwitter/uberpython.wordpress.com/575/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/twitter/uberpython.wordpress.com/575/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gostumble/uberpython.wordpress.com/575/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/stumble/uberpython.wordpress.com/575/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/godigg/uberpython.wordpress.com/575/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/digg/uberpython.wordpress.com/575/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/goreddit/uberpython.wordpress.com/575/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/reddit/uberpython.wordpress.com/575/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://stats.wordpress.com/b.gif?host=uberpython.wordpress.com&amp;blog=4565747&amp;post=575&amp;subd=uberpython&amp;ref=&amp;feed=1&quot; width=&quot;1&quot; height=&quot;1&quot; /&gt;</description>
	<pubDate>Tue, 14 Feb 2012 07:41:26 +0000</pubDate>
</item>
<item>
	<title>EmptysquarePython: Third Normal Form and Ultimate Truth</title>
	<guid>http://emptysquare.net/blog/third-normal-form-and-ultimate-truth/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=third-normal-form-and-ultimate-truth</guid>
	<link>http://emptysquare.net/blog/third-normal-form-and-ultimate-truth/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=third-normal-form-and-ultimate-truth</link>
	<description>&lt;p&gt;I have an opinion: most people learned about relational databases as if RDBMSes were designed to store the ultimate truth about some data. They figured that once the schema had been properly diagrammed and normalized, then they could load all their data into it, and finally, start doing some queries.&lt;/p&gt;
&lt;p&gt;To pick on an easy target, look at &lt;a href=&quot;http://en.wikipedia.org/wiki/Database_design&quot;&gt;Wikipedia&amp;#8217;s article on schema design&lt;/a&gt;. It summarizes the two steps a designer must take:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Determine the relationships between the different data elements.&lt;/li&gt;
&lt;li&gt;Superimpose a logical structure upon the data on the basis of these relationships.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Do you see a step that&amp;#8217;s missing? If you&amp;#8217;ve deployed and maintained a large-scale application you&amp;#8217;ll probably see what the Wikipedia authors omitted. In fact, it&amp;#8217;s the first step: Figure out what &lt;strong&gt;one&lt;/strong&gt; question your database must answer. Then, design your schema to answer that question as fast as possible. And now you&amp;#8217;re done. Come to think of it, you never had to do steps 1 and 2 at all.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s a total disconnect between the approaches of introductory SQL courses and real-world application development, and I think this disconnect is slowing down adoption of NoSQL.&lt;/p&gt;
&lt;p&gt;Consider Facebook Messages. After a (now rather well-publicized) evaluation process, &lt;a href=&quot;https://www.facebook.com/note.php?note_id=454991608919&quot;&gt;Facebook chose HBase&lt;/a&gt;, a NoSQL data store, as the main database for their message system. I haven&amp;#8217;t talked to anyone there, but I figure they chose it based on this criterion:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How fast will our database answer the question, &amp;#8220;What are this user&amp;#8217;s most recent 10 messages?&amp;#8221;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;They chose the database system that could answer that question the fastest, and they designed the best schema they could think of to answer that question. Anything else they need to ask HBase may be slow, or difficult, but that doesn&amp;#8217;t matter, because &amp;#8220;What are this user&amp;#8217;s most recent 10 messages?&amp;#8221; probably accounts for 99% of the load on their system.&lt;/p&gt;
&lt;p&gt;If you learned about databases in college, following some textbook, I expect you were guided through a long process of modeling real-world data using rows and columns, to express some profound truth about the data. Then, you were introduced to SQL, with which you could query the data. At the end of the course, maybe there was a brief discussion of database performance. Probably not.&lt;/p&gt;
&lt;p&gt;Data at the scale that the largest websites handle doesn&amp;#8217;t work that way. Large applications design their schemas to answer one question as quickly as possible, and no other considerations are significant.&lt;/p&gt;
&lt;p&gt;The next time you read about a NoSQL database you might wonder, &amp;#8220;What about foreign keys, or normalization? What about transactions? Why can&amp;#8217;t I define secondary indexes? Why are range queries prohibited?&amp;#8221; (I&amp;#8217;m just picking some limitations at random&amp;mdash;each system is different.) Consider who built these new database systems, and what their experience has been. The ideas behind NoSQL databases mostly originated at places like Google, Amazon, and Yahoo. They build huge systems, and huge systems&amp;#8217; loads are usually dominated by a handful of queries. Companies build their database systems from the ground up to optimize the performance of these queries. NoSQL databases encourage you to figure out ahead of time, &amp;#8220;What one question do I need to answer?&amp;#8221; Figure that out, and choose your database software and your schema based on that. Nothing else really matters.&lt;/p&gt;</description>
	<pubDate>Tue, 14 Feb 2012 06:31:57 +0000</pubDate>
</item>
<item>
	<title>ShiningPanda: Selenium, Python and Jenkins on Debian - 3/3</title>
	<guid>http://blog.shiningpanda.com/2012/02/selenium-python-and-jenkins-on-debian_14.html</guid>
	<link>http://blog.shiningpanda.com/2012/02/selenium-python-and-jenkins-on-debian_14.html</link>
	<description>In our &lt;a href=&quot;http://blog.shiningpanda.com/2012/01/selenium-python-and-jenkins-on-debian.html&quot; target=&quot;_blank&quot;&gt;first post&lt;/a&gt; on Selenium in Python, we saw how to prepare your continuous integration environment on Debian. In the &lt;a href=&quot;http://blog.shiningpanda.com/2012/02/selenium-python-and-jenkins-on-debian.html&quot; target=&quot;_blank&quot;&gt;second one&lt;/a&gt;, we saw how to enable Selenium tests in your existing web project. Now it's time to see how to integrate all this within Jenkins!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Global Configuration&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;First ensure that the latest version of the &lt;i&gt;ShiningPanda Plugin&lt;/i&gt; and &lt;i&gt;Xvnc Plugin&lt;/i&gt; are installed (check on &lt;i&gt;Manage Jenkins &amp;gt; Manage Plugins &amp;gt; Installed&lt;/i&gt; page). If not, look for them in the &lt;i&gt;Available&lt;/i&gt; tab and perform the installation (don't forget to restart Jenkins).&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-fgyJv19JnIY/TuhhRfeKfvI/AAAAAAAAAHQ/Ojf8V5Aomg4/s1600/plugin_manager.png&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-fgyJv19JnIY/TuhhRfeKfvI/AAAAAAAAAHQ/Ojf8V5Aomg4/s1600/plugin_manager.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Then declare all the Python installations you want to test on with the &lt;i&gt;Manage Jenkins &amp;gt; Configure System&lt;/i&gt; page (one shot configuration):&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-opFzhbxaiC0/TuhhVaWjm9I/AAAAAAAAAHY/ZDsrxbRidB4/s1600/installations.png&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-opFzhbxaiC0/TuhhVaWjm9I/AAAAAAAAAHY/ZDsrxbRidB4/s1600/installations.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;To add an installation, search the &lt;i&gt;Python&lt;/i&gt; section and click on &lt;i&gt;Add Python&lt;/i&gt;. Then give the installation a name and enter its home folder (ie. &lt;i&gt;PYTHONHOME&lt;/i&gt;).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Sample project&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;This tutorial is based on the sample described in our &lt;a href=&quot;http://blog.shiningpanda.com/2012/02/selenium-python-and-jenkins-on-debian.html&quot; target=&quot;_blank&quot;&gt;last post&lt;/a&gt;. Our goal is to test the project on several different web browsers, or in this context: Web Driver environments.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Create a new job&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-K_ml3PsAdRA/TufDJS7kIRI/AAAAAAAAAGA/_4_-PJU-344/s1600/new_job_400.png&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-K_ml3PsAdRA/TufDJS7kIRI/AAAAAAAAAGA/_4_-PJU-344/s1600/new_job_400.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;First of all, create a &lt;i&gt;New Job&lt;/i&gt;, enter its name (here &lt;i&gt;djangotutorial&lt;/i&gt;) and select &lt;i&gt;Build multi-configuration project&lt;/i&gt; before validating.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Basic setup&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-ywtW7CWvL2Q/TufDW1ggrHI/AAAAAAAAAGI/goaunXkTsF4/s1600/name_source_trigger.png&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-ywtW7CWvL2Q/TufDW1ggrHI/AAAAAAAAAGI/goaunXkTsF4/s1600/name_source_trigger.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;As usual, setup:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The description.&lt;/li&gt;&lt;li&gt;The source repository, here &lt;i&gt;https://github.com/shiningpanda/djangotutorial-selenose.git&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;The build trigger policy: checking for modifications every five minutes in this example.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Axis&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Axis provide parameters to the build. At least two axis are required for this project:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The Web Driver one to specify the web browser to use,&lt;/li&gt;&lt;li&gt;The Python one to specify the Python interpreter running the web server.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;Web Driver axis&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;To create a Web Driver axis, click on &lt;i&gt;Add axis&lt;/i&gt; in &lt;i&gt;Configuration Matrix&lt;/i&gt; section and select &lt;i&gt;User-defined axis&lt;/i&gt;. &lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-moc8XQTuMw8/TufDxSWSWZI/AAAAAAAAAGQ/UhXWDhWd63c/s1600/webdriver_axis.png&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-moc8XQTuMw8/TufDxSWSWZI/AAAAAAAAAGQ/UhXWDhWd63c/s1600/webdriver_axis.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Then:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;In &lt;i&gt;Name&lt;/i&gt; define the environment variable that will contains the Web Driver environment to test on, here &lt;i&gt;WEBDRIVER&lt;/i&gt;,&lt;/li&gt;&lt;li&gt;In &lt;i&gt;Values&lt;/i&gt; write a space separated list of Web Driver environment you want to test on, here &lt;i&gt;firefox&lt;/i&gt; and &lt;i&gt;chrome&lt;/i&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;For more informations on Web Driver environments, see &lt;a href=&quot;http://readthedocs.org/docs/selenose/en/latest/&quot; target=&quot;_blank&quot;&gt;selenose documentation&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;Python axis&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Click once more on &lt;i&gt;Add axis&lt;/i&gt; and select &lt;i&gt;Python&lt;/i&gt; to be able to select the Python interpreter running the web server.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-VQsMvalbc1U/Tuhexo8y22I/AAAAAAAAAGg/Wi2C-NcRDZQ/s1600/python_axis.png&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-VQsMvalbc1U/Tuhexo8y22I/AAAAAAAAAGg/Wi2C-NcRDZQ/s1600/python_axis.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;In this example, only Python 2.7 is tested but feel free to add additional interpreters.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Start a display&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;A display is required to run Selenium tests.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-vdqcJJ0_cAc/Tuhe4kUB94I/AAAAAAAAAGo/NoYKzuhaa80/s1600/xvnc.png&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-vdqcJJ0_cAc/Tuhe4kUB94I/AAAAAAAAAGo/NoYKzuhaa80/s1600/xvnc.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;To start one, enable &lt;i&gt;Run Xvnc during build&lt;/i&gt; in the &lt;i&gt;Build Environment&lt;/i&gt; section.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Builder&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;To be able to install all required package, a &lt;i&gt;Virtualenv Builder&lt;/i&gt; is recommended.&lt;br /&gt;&lt;br /&gt;Click on &lt;i&gt;Add build step&lt;/i&gt; in &lt;i&gt;Build&lt;/i&gt; section and select &lt;i&gt;Virtualenv Builder&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-M19KVeyFnvo/Tuhe-FQ8PEI/AAAAAAAAAGw/ShTBVjO2qkk/s1600/virtualenv_builder_400.png&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-M19KVeyFnvo/Tuhe-FQ8PEI/AAAAAAAAAGw/ShTBVjO2qkk/s1600/virtualenv_builder_400.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;In the &lt;i&gt;Command&lt;/i&gt; field enter all required steps:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Install dependencies with pip,&lt;/li&gt;&lt;li&gt;Step in &lt;i&gt;tests&lt;/i&gt; folder,&lt;/li&gt;&lt;li&gt;Run the tests using the script &lt;i&gt;run.py&lt;/i&gt; (a nose wrapper) without forgetting to specify the Web Driver to use with the &lt;i&gt;--selenium-driver=&lt;/i&gt; option (note that its value &lt;i&gt;$WEBDRIVER&lt;/i&gt; comes from the axis defined previously),&lt;/li&gt;&lt;li&gt;Convert code coverage report in XML.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Post-build actions&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-LFAwJZZ5qXA/TuhfDfJdMII/AAAAAAAAAG4/86xYGaaab5Y/s1600/post_build_actions.png&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-LFAwJZZ5qXA/TuhfDfJdMII/AAAAAAAAAG4/86xYGaaab5Y/s1600/post_build_actions.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Add all the desired post-build actions. Here Jenkins is asked to parse the XML test and coverage reports and to send mails on failure.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Results&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-hhmJlYxn_yU/TuhfIYGpkhI/AAAAAAAAAHA/ZpuMCjsUcv0/s1600/result.png&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-hhmJlYxn_yU/TuhfIYGpkhI/AAAAAAAAAHA/ZpuMCjsUcv0/s1600/result.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Finally start a new build by clicking on &lt;i&gt;Build Now&lt;/i&gt;: execution results by Web Driver environment are directly available on the main page of the project.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tips&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Testing on multiple Web Driver environments can be time and resource consuming.&lt;br /&gt;To ensure that a revision is worthwhile to test on all environments, you can execute a touchstone build first:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If this build is successful, builds on other versions will be triggered.&lt;/li&gt;&lt;li&gt;If this build fails, other versions will not be tested.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-6g1zo8wpaaI/TuhfOWxqtJI/AAAAAAAAAHI/OehiuHw2hFE/s1600/touchstone.png&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-6g1zo8wpaaI/TuhfOWxqtJI/AAAAAAAAAHI/OehiuHw2hFE/s1600/touchstone.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;To enable this option, look for a &lt;i&gt;Execute a touchstone build first&lt;/i&gt; checkbox in the &lt;i&gt;Configuration Matrix&lt;/i&gt; and check it.&lt;br /&gt;&lt;br /&gt;The syntax for &lt;i&gt;filter&lt;/i&gt; is &lt;i&gt;WEBDRIVER==&quot;&amp;lt;environment&amp;gt;&quot;&lt;/i&gt;, where &lt;i&gt;&amp;lt;environment&amp;gt;&lt;/i&gt; is the name of the Web Driver environment you want to test on first.&lt;br /&gt;Here the touchstone build is executed with Firefox (&lt;i&gt;WEBDRIVER==&quot;firefox&quot;&lt;/i&gt;) but it could also have been Chrome (&lt;i&gt;WEBDRIVER==&quot;chrome&quot;&lt;/i&gt;).&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&quot;1&quot; height=&quot;1&quot; src=&quot;https://blogger.googleusercontent.com/tracker/5534698601792655572-2870736839365490668?l=blog.shiningpanda.com&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;</description>
	<pubDate>Tue, 14 Feb 2012 03:00:01 +0000</pubDate>
</item>
<item>
	<title>Montreal Python User Group: Cloud Robotics Hackathon</title>
	<guid>http://montrealpython.org/2012/02/cloud-robotics-hackathon/</guid>
	<link>http://montrealpython.org/2012/02/cloud-robotics-hackathon/</link>
	<description>&lt;p id=&quot;magicdomid3&quot;&gt;Hello Montreal hackers&lt;/p&gt;
&lt;p id=&quot;magicdomid9&quot;&gt;The cloud robotics week-end is happening the 2nd, 3rd and 4th of March.&lt;/p&gt;
&lt;p&gt;Come hack on robots and web services to create cool projects in robotics. See   &lt;a href=&quot;http://roboticshackathon.com/&quot;&gt;http://roboticshackathon.com/&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;We are waiting for you if you would like to create a team Montreal-Python and if you would like to join us for this week-end of hack and programming.&lt;/p&gt;</description>
	<pubDate>Tue, 14 Feb 2012 02:38:37 +0000</pubDate>
</item>
<item>
	<title>Stephen Ferg: Backing up your email</title>
	<guid>http://pythonconquerstheuniverse.wordpress.com/2012/02/13/backing-up-your-email/</guid>
	<link>http://pythonconquerstheuniverse.wordpress.com/2012/02/13/backing-up-your-email/</link>
	<description>&lt;p&gt;Just in case someone might find this useful &amp;#8230;&lt;/p&gt;
&lt;p&gt;I recently had something bad happen to me.  I use Thunderbird (on Windows Vista) as my email client.  I asked Thunderbird to compact my email files, and it wiped out a bunch of my email messages.  (I think that one of my email files must have been corrupt, and when I compacted it, the compaction process wiped out messages that should not have been wiped out.)  &lt;/p&gt;
&lt;p&gt;You can recover deleted email messages &amp;#8230; but not after the email file has been compacted.  So the messages were not recoverable. Bummer. &lt;/p&gt;
&lt;p&gt;The upside is that this nasty incident led me to learn some things. &lt;/p&gt;
&lt;p&gt;One thing that I learned was that the disk backup utility that I was using at the time did NOT backup my email files.  The email files were stored in a directory called AppData, and the AppData directory is a &amp;#8220;hidden&amp;#8221; directory.  So the backup utility didn&amp;#8217;t see the AppData directory, and didn&amp;#8217;t back it up.  So I had no backup of the deleted messages.&lt;/p&gt;
&lt;p&gt;Learning that led me to investigate ways to backup my email files, and I found this: &lt;a href=&quot;http://www.makeuseof.com/tag/5-ways-to-keep-your-emails-backed-up/&quot; title=&quot;Five ways to keep your emails backed up&quot; target=&quot;_blank&quot;&gt;Five ways to keep your emails backed up&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For backing up Thunderbird files, it recommends MozBackup as being fast, free and easy to use.  So I tried MozBackup, and those claims seem to be true.&lt;/p&gt;
&lt;p&gt;Now I&amp;#8217;m evaluating different disk backup options.&lt;/p&gt;
&lt;p&gt;The take-away here is that &lt;strong&gt;you need to pay special attention to backing up your email files.&lt;/strong&gt; So if you&amp;#8217;re not backing up your email files, take a look at &lt;a href=&quot;http://www.makeuseof.com/tag/5-ways-to-keep-your-emails-backed-up/&quot; title=&quot;Five ways to keep your emails backed up&quot; target=&quot;_blank&quot;&gt;Five ways to keep your emails backed up&lt;/a&gt; (and read the comments, which are useful) or google something like &lt;a href=&quot;http://www.google.com/search?q=email+backup&quot; title=&quot;google EMAIL BACKUP&quot; target=&quot;_blank&quot;&gt;&amp;#8220;email backup&amp;#8221;&lt;/a&gt;.   &lt;/p&gt;
&lt;p&gt;[Note that this applies only if you are using an email client such as Thunderbird, Outlook, Outlook Express, etc.  If you don't use an email client, and do all of your email work through a Web interface to your Internet Service Provider, then this is not an issue.]&lt;/p&gt;
&lt;br /&gt;  &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gocomments/pythonconquerstheuniverse.wordpress.com/1532/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/comments/pythonconquerstheuniverse.wordpress.com/1532/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/godelicious/pythonconquerstheuniverse.wordpress.com/1532/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/delicious/pythonconquerstheuniverse.wordpress.com/1532/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gofacebook/pythonconquerstheuniverse.wordpress.com/1532/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/facebook/pythonconquerstheuniverse.wordpress.com/1532/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gotwitter/pythonconquerstheuniverse.wordpress.com/1532/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/twitter/pythonconquerstheuniverse.wordpress.com/1532/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/gostumble/pythonconquerstheuniverse.wordpress.com/1532/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/stumble/pythonconquerstheuniverse.wordpress.com/1532/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/godigg/pythonconquerstheuniverse.wordpress.com/1532/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/digg/pythonconquerstheuniverse.wordpress.com/1532/&quot; /&gt;&lt;/a&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;http://feeds.wordpress.com/1.0/goreddit/pythonconquerstheuniverse.wordpress.com/1532/&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://feeds.wordpress.com/1.0/reddit/pythonconquerstheuniverse.wordpress.com/1532/&quot; /&gt;&lt;/a&gt; &lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;http://stats.wordpress.com/b.gif?host=pythonconquerstheuniverse.wordpress.com&amp;blog=9223888&amp;post=1532&amp;subd=pythonconquerstheuniverse&amp;ref=&amp;feed=1&quot; width=&quot;1&quot; height=&quot;1&quot; /&gt;</description>
	<pubDate>Tue, 14 Feb 2012 02:17:03 +0000</pubDate>
</item>
<item>
	<title>EmptysquarePython: Philly MongoDB User Group: Python, MongoDB, and Asynchronous Web Frameworks</title>
	<guid>http://emptysquare.net/blog/philly-mongodb-user-group-python-mongodb-and-asynchronous-web-frameworks/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=philly-mongodb-user-group-python-mongodb-and-asynchronous-web-frameworks</guid>
	<link>http://emptysquare.net/blog/philly-mongodb-user-group-python-mongodb-and-asynchronous-web-frameworks/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=philly-mongodb-user-group-python-mongodb-and-asynchronous-web-frameworks</link>
	<description>&lt;p&gt;&lt;img src=&quot;http://emptysquare.net/blog/wp-content/uploads/2012/02/800px-Philadelphia_Panorama_From_Camden.jpg&quot; alt=&quot;Philadelphia Panorama From Camden&quot; title=&quot;800px-Philadelphia_Panorama_From_Camden.JPG&quot; border=&quot;0&quot; width=&quot;450&quot; height=&quot;92&quot; /&gt;&lt;br /&gt;
&lt;a href=&quot;http://en.wikipedia.org/wiki/File:Philadelphia_Panorama_From_Camden.JPG&quot;&gt;&lt;span&gt;Photo (C) Parent5446&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll be recapping last week&amp;#8217;s talk on &lt;a href=&quot;http://emptysquare.net/blog/this-thursday-a-talk-on-python-mongodb-and-asynchronous-web-frameworks/&quot;&gt;Python, MongoDB, and Asynchronous Web Frameworks&lt;/a&gt;  this Thursday at 7pm, in Philadelphia, at the Philly MongoDB User Group&amp;#8217;s inaugural meetup. We&amp;#8217;ll be at the Devnuts office, at 908 North 3rd Street. We&amp;#8217;ll have pizza, naturally.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.meetup.com/Philladelphia-MongoDB-User-Group/events/47409232/&quot;&gt;First Philly MongoDB User Group&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Mon, 13 Feb 2012 20:26:39 +0000</pubDate>
</item>
<item>
	<title>Cormoran Project: Continuous integration with Travis</title>
	<guid>http://feedproxy.google.com/~r/cormoran-project/~3/ifX5Yq2KdMM/continuous-integration-with-travis.html</guid>
	<link>http://feedproxy.google.com/~r/cormoran-project/~3/ifX5Yq2KdMM/continuous-integration-with-travis.html</link>
	<description>We recently &lt;a href=&quot;http://travis-ci.org/#%21/jaimegildesagredo/cormoran&quot;&gt;started using&lt;/a&gt; &lt;a href=&quot;http://travis-ci.org/&quot;&gt;Travis CI&lt;/a&gt; as &lt;a href=&quot;http://en.wikipedia.org/wiki/Continuous_integration&quot;&gt;continuous integration&lt;/a&gt; server for Cormoran. &lt;a href=&quot;http://about.travis-ci.org/docs/&quot;&gt;Travis&lt;/a&gt; is a distributed build system for the open source community used by projects like Ruby, Rails, Rubinius, Rubygems and a large number of open source projects.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot;&gt;
&lt;a href=&quot;http://2.bp.blogspot.com/-xkLyq1tL1i0/TzhfAC5U6sI/AAAAAAAAAF4/Mdv2Uxiw_eg/s1600/cormoran-travisci.png&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;215&quot; src=&quot;http://2.bp.blogspot.com/-xkLyq1tL1i0/TzhfAC5U6sI/AAAAAAAAAF4/Mdv2Uxiw_eg/s320/cormoran-travisci.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Travis is integrated with GitHub and supports various programming languages like &lt;i&gt;Ruby&lt;/i&gt;, &lt;i&gt;Node.js&lt;/i&gt; or &lt;i&gt;PHP&lt;/i&gt;. Although Travis doesn't support Python language it's possible to use it with Python projects. Here's how to do it ;)&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&quot;more&quot;&gt;&lt;/a&gt;First of all you need to &lt;a href=&quot;http://travis-ci.org/users/auth/github&quot;&gt;sign in&lt;/a&gt; through GitHub and follow the getting started guide &lt;a href=&quot;http://about.travis-ci.org/docs/user/getting-started/&quot;&gt;here&lt;/a&gt;. In the third step you need to create a &lt;i&gt;.travis.yml&lt;/i&gt; &lt;a href=&quot;https://github.com/jaimegildesagredo/cormoran/blob/master/.travis.yml&quot;&gt;configuration&lt;/a&gt; file to tell Travis how to build your project. This is an example of the structure that must have.&lt;br /&gt;
&lt;br /&gt;
&lt;table class=&quot;highlighttable&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td class=&quot;linenos&quot;&gt;&lt;div class=&quot;linenodiv&quot;&gt;
&lt;pre&gt;1
2
3
4
5
6
7
8
9&lt;/pre&gt;
&lt;/div&gt;
&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;
&lt;pre&gt;&lt;span class=&quot;l-Scalar-Plain&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;python&lt;/span&gt;
&lt;span class=&quot;l-Scalar-Plain&quot;&gt;before_script&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;virtualenv cormoran_env&lt;/span&gt;
    &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;source cormoran_env/bin/activate&lt;/span&gt;
    &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;pip install nose pyhamcrest pydoubles coverage&lt;/span&gt;

&lt;span class=&quot;l-Scalar-Plain&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p-Indicator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;python setup.py develop&lt;/span&gt;
    &lt;span class=&quot;p-Indicator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;l-Scalar-Plain&quot;&gt;nosetests tests/unit&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
There are only three sections: &lt;i&gt;language&lt;/i&gt;, &lt;i&gt;before_script&lt;/i&gt; and &lt;i&gt;script&lt;/i&gt;. The first section tells Travis the programming language of the project. &lt;span class=&quot;short_text&quot; id=&quot;result_box&quot; lang=&quot;en&quot;&gt;&lt;span class=&quot;hps&quot;&gt;We use&lt;/span&gt; &lt;span class=&quot;hps&quot;&gt;Python&lt;/span&gt;, &lt;span class=&quot;hps&quot;&gt;although is&lt;/span&gt; &lt;span class=&quot;hps&quot;&gt;not supported, to pass &lt;a href=&quot;https://github.com/travis-ci/travis-lint&quot;&gt;travis-lint&lt;/a&gt; check.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;short_text&quot; id=&quot;result_box&quot; lang=&quot;en&quot;&gt;&lt;span class=&quot;hps&quot;&gt;The next two sections are a set of shell commands to build the project. The &lt;i&gt;before_script&lt;/i&gt; section is executed before main script and &lt;i&gt;script&lt;/i&gt; is the main script to build your project.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;short_text&quot; id=&quot;result_box&quot; lang=&quot;en&quot;&gt;&lt;span class=&quot;hps&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;short_text&quot; id=&quot;result_box&quot; lang=&quot;en&quot;&gt;&lt;span class=&quot;hps&quot;&gt;We basically create a virtual environment and install the dependencies and then build project and run tests.&lt;/span&gt;&lt;span class=&quot;hps&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;&quot; id=&quot;result_box&quot; lang=&quot;en&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;&quot; id=&quot;result_box&quot; lang=&quot;en&quot;&gt;That's all! &lt;span class=&quot;hps&quot;&gt;We already have our&lt;/span&gt; &lt;span class=&quot;hps&quot;&gt;continuous integration&lt;/span&gt; &lt;span class=&quot;hps&quot;&gt;system&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;&quot; id=&quot;result_box&quot; lang=&quot;en&quot;&gt;&lt;a href=&quot;http://about.travis-ci.org/docs/&quot;&gt;Travis CI Documentation&lt;/a&gt;&lt;/span&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&quot;1&quot; height=&quot;1&quot; src=&quot;https://blogger.googleusercontent.com/tracker/6509482405829300009-8338276318308972847?l=cormoran-project.blogspot.com&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://feedads.g.doubleclick.net/~a/C5J8FlwUiXQczrwHzNYsyIZf1zM/0/da&quot;&gt;&lt;img src=&quot;http://feedads.g.doubleclick.net/~a/C5J8FlwUiXQczrwHzNYsyIZf1zM/0/di&quot; border=&quot;0&quot; ismap=&quot;true&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://feedads.g.doubleclick.net/~a/C5J8FlwUiXQczrwHzNYsyIZf1zM/1/da&quot;&gt;&lt;img src=&quot;http://feedads.g.doubleclick.net/~a/C5J8FlwUiXQczrwHzNYsyIZf1zM/1/di&quot; border=&quot;0&quot; ismap=&quot;true&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/cormoran-project/~4/ifX5Yq2KdMM&quot; height=&quot;1&quot; width=&quot;1&quot; /&gt;</description>
	<pubDate>Mon, 13 Feb 2012 18:42:44 +0000</pubDate>
</item>
<item>
	<title>Jesse Noller: A letter to my love, my friend, my wife.</title>
	<guid>http://feedproxy.google.com/~r/Jessenollercom/~3/9IJ_iD5s6fI/</guid>
	<link>http://feedproxy.google.com/~r/Jessenollercom/~3/9IJ_iD5s6fI/</link>
	<description>&lt;p&gt;&lt;img src=&quot;http://jessenoller.com/wp-content/uploads/2012/02/IMG_0239.jpg&quot; border=&quot;0&quot; alt=&quot;IMG 0239&quot; width=&quot;300&quot; height=&quot;225&quot; /&gt;&lt;/p&gt;
&lt;p&gt;A letter to my love, my friend, my wife and my partner — Dusty:&lt;/p&gt;
&lt;p&gt;I know it’s the day before Valentines — some things can’t wait just for a day.&lt;/p&gt;
&lt;p&gt;Ten years — that’s how long we’ve been with one another. Ten years feels like a lifetime — so much has changed — our lives altered in subtle — and not so subtle ways by the gentle currents of each other. In the time I’ve known you, we have both changed for the better — we compliment and act as one another’s confidant, friend, partner and lovers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“The most powerful symptom of love is a tenderness which becomes at times almost insupportable.” — Victor Hugo&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://jessenoller.com/wp-content/uploads/2012/02/wedding-451-copy.jpg&quot; border=&quot;0&quot; alt=&quot;Wedding 451 copy&quot; width=&quot;300&quot; height=&quot;225&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We’ve been through our times of trial — little things like accidentally renting an apartment in a war zone (my bad!) — and much bigger things from health, to finances, to not know what we were doing or where we were going. We both know that this past year has been probably the one most filled with trials and tribulations.&lt;/p&gt;
&lt;p&gt;We’ve sat across from one another not knowing what we were going to do, we’ve held each others hands watching our infant daughter laying in a hospital bed — I’ve held your hand at your bedside in watching your pain and not knowing what to do about it, except to sit there and watch your pain. We’ve been through a lot in ten years.&lt;/p&gt;
&lt;p&gt;Despite the trials — we have made each other stronger. You have changed who I am in such fundamental and subtle ways, that I attribute much of who I am now, to you. You have made me happier, stronger, more empathetic — you have also given me the cherished gift of your love, your tears and support in my times of pain.&lt;/p&gt;
&lt;p&gt;You have given me more than just your love; you gave me our first daughter Abby — who might as well be a tiny clone of myself in female form (god help us all), who despite her willfulness and strong personality makes my heart jump each time I hear her laugh, each time she runs to me and hugs me and tell me she loves me.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://jessenoller.com/wp-content/uploads/2012/02/IMG_3690.jpg&quot; border=&quot;0&quot; alt=&quot;IMG 3690&quot; width=&quot;300&quot; height=&quot;225&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Abby is almost five! Five years old! All parents gush about how smart their children are — but we both know there’s something special and unique about her. There’s more to her than a pushy 4.5 year old, there’s something magical about her that we both see. I can not verbalize or put to words my thanks to you for her. She’s a gift you’ve given to me.&lt;/p&gt;
&lt;p&gt;Then there is Addison, our bubbling eight month old. What can I say about someone who greats me with a smile and a laugh whether it’s five in the morning, or me just coming home from a hard day at work?&lt;/p&gt;
&lt;p&gt;Addison is more than a gift; she’s a blessing — the past year shows that even in our darkest hours, sitting there in a hospital not knowing what will happen, something watches over us. Addison’s happiness and flourishing is not just due to doctors, or therapists — it’s directly tied to the amazing love and care you provide to her.&lt;/p&gt;
&lt;p&gt;Every time I look at Addison, I see an extension of you — your smile, your happiness (and when she giggles when she rams me with her walker, your sense of humor). Addison is again, a gift and blessing you’ve given me.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://jessenoller.com/wp-content/uploads/2012/02/IMG_4457.jpg&quot; border=&quot;0&quot; alt=&quot;IMG 4457&quot; width=&quot;300&quot; height=&quot;225&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You’ve given me so much; you’ve changed me so much. You’ve made me look outside of myself and think of others — you, our daughters, you’ve driven me to try to change the world and help as many people as I can. You’ve driven me to be better — a better man, a better husband, father and human.&lt;/p&gt;
&lt;p&gt;Times change — people change. We have our hard times — we have those times when we both want to go lock ourselves in the bathroom just to get a moment of quiet. We have times when we just don’t know what will come, and times when we wish what had came had not. We have persevered over the hard times we’ve faced until now, and those hard times we face now, we face together, as one.&lt;/p&gt;
&lt;p&gt;You are beautiful — you always have been, you are strong — you are honest and critical. I might say half-jokingly that you’re my better half some times — but you really and truly are (You are also better looking than me!).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://jessenoller.com/wp-content/uploads/2012/02/wedding-144.jpg&quot; border=&quot;0&quot; alt=&quot;Wedding 144&quot; width=&quot;300&quot; height=&quot;200&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You, and the gifts have given me — our daughters, have given me more than a reason to just keep working, just to keep moving from day to day. You’ve given me a reason to truly live, to truly push myself beyond anything I could have imagined eleven years ago. You’ve given me a place and arms to cry in, to laugh in, and to grow in. You’ve given me a view of life, of living, of loving I never dreamed of having.&lt;/p&gt;
&lt;p&gt;I know that once again we face hard times. I thought that perhaps this year might be a little easier on us — but so far, we both know it isn’t, and there are probably harder times coming for us. I am sorry that I can not always give to you all the things you so richly deserve — I’d give you anything, I’d buy you anything if I could. I am sorry I don’t have anything I can give you today other than my words — darn those hard times!&lt;/p&gt;
&lt;p&gt;My gift to you is this — my expression of how much I truly value you, cherish you and how grateful I am — in spite of all the hard times — the good times, the memories, our daughters and most importantly our love. I am but a broken man, but with you I am whole.&lt;/p&gt;
&lt;p&gt;Thank you for being who you are.&lt;/p&gt;
&lt;p&gt;Thank you for being with me.&lt;/p&gt;
&lt;p&gt;Thank you for loving me.&lt;/p&gt;
&lt;p&gt;Thank you for letting me love you in return.&lt;/p&gt;
&lt;p&gt;Jesse&lt;/p&gt;
&lt;p&gt;p.s. Churchill loves you too:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://jessenoller.com/wp-content/uploads/2012/02/IMG_4461.jpg&quot; border=&quot;0&quot; alt=&quot;IMG 4461&quot; width=&quot;300&quot; height=&quot;225&quot; /&gt;&lt;/p&gt;
 &lt;p&gt;&lt;a href=&quot;http://jessenoller.com/?flattrss_redirect&amp;id=1132&amp;md5=b58809045d8944e92b10181ec3ab518a&quot; title=&quot;Flattr&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://jessenoller.com/wp-content/plugins/flattr/img/flattr-badge-large.png&quot; alt=&quot;flattr this!&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Mon, 13 Feb 2012 17:32:53 +0000</pubDate>
</item>
<item>
	<title>PyPy Development: A Larger Example for the Flow Graph Language</title>
	<guid>http://feedproxy.google.com/~r/PyPyStatusBlog/~3/sautdC5jeto/larger-example-for-flow-graph-language.html</guid>
	<link>http://feedproxy.google.com/~r/PyPyStatusBlog/~3/sautdC5jeto/larger-example-for-flow-graph-language.html</link>
	<description>&lt;h2&gt;Part 4 of Comparing Partial Evaluation to Tracing&lt;/h2&gt;
&lt;p&gt;This is the fourth and final blog post in a series about comparing partial evaluation and
tracing. We've come a long way: In the &lt;a class=&quot;reference external&quot; href=&quot;http://morepypy.blogspot.com/2012/01/comparing-partial-evaluation-and.html&quot;&gt;first post of the series&lt;/a&gt; I showed an interpreter for a small flow-graph
language together with a partial evaluator it. In the &lt;a class=&quot;reference external&quot; href=&quot;http://morepypy.blogspot.com/2012/01/simple-tracer-for-flow-graph-language.html&quot;&gt;second post&lt;/a&gt; I showed how a tracer for
the same language works and how it relates to both execution and to partial
evaluation. The &lt;a class=&quot;reference external&quot; href=&quot;http://morepypy.blogspot.com/2012/02/optimizing-traces-of-flow-graph.html&quot;&gt;third post&lt;/a&gt; described an optimizer for traces.&lt;/p&gt;
&lt;p&gt;In this final post we can compare and contrast the two different approaches of
tracing and partial evaluation by means of an example. The programs in the flow
chart language seen so far have been rather small, so I want to give an example
of a larger program: an interpreter for an extremely simple bytecode
instruction set. I will look at how the partial evaluator deals with that
interpreter, and
what the tracer does with it. The code for
that, as well as all the code of the series can be found here: &lt;a class=&quot;reference external&quot; href=&quot;http://paste.pocoo.org/show/550282/&quot;&gt;http://paste.pocoo.org/show/550282/&lt;/a&gt; (some small
additions have been made, such as a nicer way to print traces).&lt;/p&gt;
&lt;h2&gt;A Bytecode Interpreter&lt;/h2&gt;
&lt;p&gt;Writing programs in the flow graph language is painful, but I still want to give
an example that is a bit more interesting than the tiny ones that we've seen so
far. The example is an interpreter for the bytecode of a very trivial
register-based language. The language has four registers, one of which is an
accumulator on which all the actual operations are performed.&lt;/p&gt;
&lt;p&gt;The opcodes of the language are:&lt;/p&gt;
&lt;ul class=&quot;simple&quot;&gt;
&lt;li&gt;&lt;tt class=&quot;docutils literal&quot;&gt;jump_if_a&lt;/tt&gt;, jumps to a target address when the accumulator is non-zero&lt;/li&gt;
&lt;li&gt;&lt;tt class=&quot;docutils literal&quot;&gt;mov_a_r0&lt;/tt&gt;, &lt;tt class=&quot;docutils literal&quot;&gt;mov_a_r1&lt;/tt&gt;, &lt;tt class=&quot;docutils literal&quot;&gt;mov_a_r2&lt;/tt&gt; move the value of the accumulator to
the respective register&lt;/li&gt;
&lt;li&gt;&lt;tt class=&quot;docutils literal&quot;&gt;mov_r0_a&lt;/tt&gt;, &lt;tt class=&quot;docutils literal&quot;&gt;mov_r1_a&lt;/tt&gt;, &lt;tt class=&quot;docutils literal&quot;&gt;mov_r2_a&lt;/tt&gt; move the value of a register to
the accumulator&lt;/li&gt;
&lt;li&gt;&lt;tt class=&quot;docutils literal&quot;&gt;add_r0_to_a&lt;/tt&gt;, &lt;tt class=&quot;docutils literal&quot;&gt;add_r1_to_a&lt;/tt&gt;, &lt;tt class=&quot;docutils literal&quot;&gt;add_r2_to_a&lt;/tt&gt; add the value of the
register to the accumulator&lt;/li&gt;
&lt;li&gt;&lt;tt class=&quot;docutils literal&quot;&gt;decr_a&lt;/tt&gt; decrement the accumulator&lt;/li&gt;
&lt;li&gt;&lt;tt class=&quot;docutils literal&quot;&gt;return_a&lt;/tt&gt; stop the program and print the accumulator&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The interpreter has a main loop that reads the opcode at the current program
counter, does a (lengthy) dispatch to the right bytecode via a series of if
statements and then executes the right opcode. Afterwards the next opcode is
treated equivalently.&lt;/p&gt;
&lt;p&gt;Here is a part of the source code in the flow graph language. As pseudocode:&lt;/p&gt;
&lt;pre class=&quot;literal-block&quot;&gt;
bytecode_loop:
    opcode = bytecode[pc]
    pc = pc + 1
    c = opcode == 'jump_if_a'
    if c goto op_jump_if_a else goto not_jump_if_a

# select the right bytecode via a long series of if statements
not_jump_if_a:
    c = opcode == 'mov_a_r0'
    if y goto op_mov_a_r0 else goto not_mov_a_r0
not_mov_a_r0:
    c = opcode == 'mov_a_r0'
    if y goto op_mov_a_r1 else goto not_mov_a_r1
...

# bytecode implementations
op_mov_a_r0:
    r0 = a
    goto bytecode_loop

op_jump_if_a:
    c = a == 0
    target = bytecode[pc]
    pc += 1
    if c goto bytecode_loop else goto op_jump_if_a_jump

op_jump_if_a_jump:
    pc = target
    goto bytecode_loop
...
&lt;/pre&gt;
&lt;p&gt;And actually working, as Prolog facts (the full implementation can be found at
the link above):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;% bytecode dispatch loop&lt;/span&gt;
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;bytecode_loop&lt;/span&gt;,
      &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;, &lt;span&gt;readlist&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;), &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;),
      &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;, &lt;span&gt;add&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;1&lt;/span&gt;),
      &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;eq&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;jump_if_a&lt;/span&gt;),
      &lt;span&gt;if&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;op_jump_if_a&lt;/span&gt;, &lt;span&gt;not_jump_if_a&lt;/span&gt;))))).

&lt;span&gt;% select the right bytecode via a long series of if statements&lt;/span&gt;
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_jump_if_a&lt;/span&gt;,
      &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;eq&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;mov_a_r0&lt;/span&gt;),
      &lt;span&gt;if&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;op_mov_a_r0&lt;/span&gt;, &lt;span&gt;not_mov_a_r0&lt;/span&gt;))).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_mov_a_r0&lt;/span&gt;,
      &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;eq&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;mov_a_r1&lt;/span&gt;),
      &lt;span&gt;if&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;op_mov_a_r1&lt;/span&gt;, &lt;span&gt;not_mov_a_r1&lt;/span&gt;))).
...

&lt;span&gt;% bytecode implementations&lt;/span&gt;
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;op_jump_if_a&lt;/span&gt;,
      &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;eq&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;0&lt;/span&gt;),
      &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;target&lt;/span&gt;, &lt;span&gt;readlist&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;), &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;),
      &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;, &lt;span&gt;add&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;1&lt;/span&gt;),
      &lt;span&gt;if&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;bytecode_loop&lt;/span&gt;, &lt;span&gt;op_jump_if_a_jump&lt;/span&gt;))))).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;op_jump_if_a_jump&lt;/span&gt;,
      &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;target&lt;/span&gt;),
      &lt;span&gt;promote&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;, &lt;span&gt;bytecode_loop&lt;/span&gt;))).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;op_mov_a_r0&lt;/span&gt;,
      &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;), &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;bytecode_loop&lt;/span&gt;))).
...
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;tt class=&quot;docutils literal&quot;&gt;bytecode_loop&lt;/tt&gt; block is the main dispatch loop. It reads an opcode out of the
bytecode list at the program counter position, then has a long series of &lt;tt class=&quot;docutils literal&quot;&gt;if&lt;/tt&gt;
statements that compares the current opcode to the various existing opcodes.
The full code of the interpreter can be found under the link above.&lt;/p&gt;
&lt;p&gt;The bytecodes of the interpreter don't really permit hugely complex
programs, but it can be used to write a program that computes the square of a
number with the following program:&lt;/p&gt;
&lt;pre class=&quot;literal-block&quot;&gt;
mov_a_r0     # r0 = a
mov_a_r1     # r1 = a
# 2:
mov_r0_a     # r0--
decr_a
mov_a_r0
mov_r2_a     # r2 += a
add_r1_to_a
mov_a_r2
mov_r0_a     # if r0!=0: goto 2
jump_if_a 2
mov_r2_a     # return r2
return_a
&lt;/pre&gt;
&lt;h2&gt;Partially Evaluating the Bytecode Interpreter&lt;/h2&gt;
&lt;p&gt;The partial evaluator from the first blog post can be easily used to partially
evaluate the bytecode interpreter. The static input is the bytecode for
computing the square and the initial program counter value, as given above. The
dynamic input are the content of the accumulator (the number to be squared).
This can be done as follows:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;?-&lt;/span&gt; &lt;span&gt;bytecode_square&lt;/span&gt;(&lt;span&gt;B&lt;/span&gt;),
&lt;span&gt;Env&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; [&lt;span&gt;bytecode&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;, &lt;span&gt;pc&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;],
&lt;span&gt;do_pe&lt;/span&gt;(&lt;span&gt;bytecode_loop&lt;/span&gt;, &lt;span&gt;Env&lt;/span&gt;, &lt;span&gt;Label&lt;/span&gt;),
&lt;span&gt;REnv&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; [&lt;span&gt;a&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;, &lt;span&gt;r0&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;, &lt;span&gt;r1&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;, &lt;span&gt;r2&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;],
&lt;span&gt;interp&lt;/span&gt;(&lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;Label&lt;/span&gt;), &lt;span&gt;REnv&lt;/span&gt;), &lt;span&gt;listing&lt;/span&gt;(&lt;span&gt;block&lt;/span&gt;).
&lt;span&gt;256&lt;/span&gt;
:- &lt;span&gt;dynamic&lt;/span&gt; &lt;span&gt;block&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;.

&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;lots&lt;/span&gt; &lt;span&gt;of&lt;/span&gt; &lt;span&gt;generated&lt;/span&gt; &lt;span&gt;code&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The code that is generated by the partial evaluation process is somewhat hard to
read. It contains a lot of passages like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;...
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;op_return_a1&lt;/span&gt;, &lt;span&gt;print_and_stop&lt;/span&gt;(&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;))).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_decr_a1&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;op_return_a1&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_add_r2_to_a2&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;not_decr_a1&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_add_r1_to_a2&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;not_add_r2_to_a2&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_add_r0_to_a3&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;not_add_r1_to_a2&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_mov_r2_a3&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;not_add_r0_to_a3&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_mov_r1_a5&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;not_mov_r2_a3&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_mov_r0_a5&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;not_mov_r1_a5&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_mov_a_r27&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;not_mov_r0_a5&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_mov_a_r18&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;not_mov_a_r27&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_mov_a_r09&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;not_mov_a_r18&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;not_jump_if_a11&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;not_mov_a_r09&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;bytecode_loop12&lt;/span&gt;, &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;not_jump_if_a11&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;op_mov_r2_a2&lt;/span&gt;, &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r2&lt;/span&gt;), &lt;span&gt;jump&lt;/span&gt;(&lt;span&gt;bytecode_loop12&lt;/span&gt;))).
...
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I.e. lots of blocks that do nothing but jump to another block, interspersed with
some blocks that contain an actual operation. I cleaned the output up manually
and got something like the following (this sort of cleanup is something a good
partial evaluation system would do itself, after partial evaluation has
occurred):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;bytecode_loop1&lt;/span&gt;,
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;),
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;r1&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;),
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;),
    &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;sub&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;1&lt;/span&gt;),
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;),
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r2&lt;/span&gt;),
    &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;add&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;), &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r1&lt;/span&gt;),
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;r2&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;),
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;),
    &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;eq&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;0&lt;/span&gt;),
    &lt;span&gt;if&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;bytecode_loop11&lt;/span&gt;, &lt;span&gt;op_jump_if_a_jump1&lt;/span&gt;)))))))))))).

&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;bytecode_loop11&lt;/span&gt;,
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r2&lt;/span&gt;),
    &lt;span&gt;print_and_stop&lt;/span&gt;(&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;))).

&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;op_jump_if_a_jump1&lt;/span&gt;,
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;),
    &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;sub&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;1&lt;/span&gt;),
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;),
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r2&lt;/span&gt;),
    &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;add&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;), &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r1&lt;/span&gt;),
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;r2&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;),
    &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;, &lt;span&gt;same&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;),
    &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;eq&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;0&lt;/span&gt;),
    &lt;span&gt;if&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;bytecode_loop11&lt;/span&gt;, &lt;span&gt;op_jump_if_a_jump1&lt;/span&gt;)))))))))).
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What do we see here? The partial evaluator has generated a block &lt;tt class=&quot;docutils literal&quot;&gt;bytecode_loop1&lt;/tt&gt;,
which corresponds to the initialization opcodes &lt;tt class=&quot;docutils literal&quot;&gt;mov_a_r0&lt;/tt&gt; and &lt;tt class=&quot;docutils literal&quot;&gt;mov_a_r1&lt;/tt&gt; together
with one iteration of the loop. Then it either jumps to a copy of the main loop
(label &lt;tt class=&quot;docutils literal&quot;&gt;op_jump_if_a_jump1&lt;/tt&gt;) or to block &lt;tt class=&quot;docutils literal&quot;&gt;bytecode_loop11&lt;/tt&gt;, which prints the result
and then stops. The residual code does exactly what the bytecode did: It
squares the accumulator then prints that. All the uses of the &lt;tt class=&quot;docutils literal&quot;&gt;bytecode&lt;/tt&gt; and
&lt;tt class=&quot;docutils literal&quot;&gt;pc&lt;/tt&gt; variable are gone.&lt;/p&gt;
&lt;p&gt;Why did the partial evaluator produce two copies of the main loop that
look the same? The reason for that is that in the second copy, the additional
static information &lt;tt class=&quot;docutils literal&quot;&gt;target = 2&lt;/tt&gt; is known, where &lt;tt class=&quot;docutils literal&quot;&gt;target&lt;/tt&gt; is a variable in
the interpreter source that stores the jump target, for very brief periods of
time. This additional static information does not have any effect on the
residual code, so the same code is uselessly generated twice. This is an
example of overspecialization.&lt;/p&gt;
&lt;h2&gt;Tracing the Interpreter&lt;/h2&gt;
&lt;p&gt;In this section we will look at what happens if we try to trace the interpreter.
The naive way of doing that yields traces that are not very useful, because they
abort after one iteration. We will look at a way of avoiding this problem. The
problems described in this section are at the core of the paper &lt;a class=&quot;reference external&quot; href=&quot;https://bitbucket.org/pypy/extradoc/src/tip/talk/icooolps2009/bolz-tracing-jit-final.pdf&quot;&gt;Tracing the
meta-level: PyPy's tracing JIT compiler&lt;/a&gt; (that paper uses a slightly more
advanced version of the bytecode interpreter as an example).&lt;/p&gt;
&lt;p&gt;To trace the interpreter, it is useful to change the &lt;tt class=&quot;docutils literal&quot;&gt;bytecode_loop&lt;/tt&gt; block from above
to always promote the &lt;tt class=&quot;docutils literal&quot;&gt;bytecode&lt;/tt&gt; and the &lt;tt class=&quot;docutils literal&quot;&gt;pc&lt;/tt&gt; variables, because without
knowing them the trace produced is not really interesting. This is similar to
making these variables static in the partial evaluation example above:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;bytecode_loop&lt;/span&gt;,
      &lt;span&gt;promote&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;, &lt;span&gt;bytecode_loop_promote_bytecode&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;bytecode_loop_promote_bytecode&lt;/span&gt;,
      &lt;span&gt;promote&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;, &lt;span&gt;bytecode_loop_promote_pc&lt;/span&gt;)).
&lt;span&gt;block&lt;/span&gt;(&lt;span&gt;bytecode_loop_promote_pc&lt;/span&gt;,
      &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;, &lt;span&gt;readlist&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;), &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;),
      &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;, &lt;span&gt;add&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;1&lt;/span&gt;),
      &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;eq&lt;/span&gt;, &lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;), &lt;span&gt;const&lt;/span&gt;(&lt;span&gt;0&lt;/span&gt;),
      &lt;span&gt;if&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;, &lt;span&gt;op_jump_if_a&lt;/span&gt;, &lt;span&gt;not_jump_if_a&lt;/span&gt;))))).
...
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The rest of the interpreter stays unchanged.&lt;/p&gt;
&lt;p&gt;To trace the interpreter we would start naively at the &lt;tt class=&quot;docutils literal&quot;&gt;bytecode_loop&lt;/tt&gt; label, because
that's the label in the interpreter that is jumped to most often (which a
profiler could establish easily). The following command can be used for that
(this output prints traces in a slightly more readable way than in previous blog
posts):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;?-&lt;/span&gt; &lt;span&gt;bytecode_square&lt;/span&gt;(&lt;span&gt;B&lt;/span&gt;),
        &lt;span&gt;A&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;16&lt;/span&gt;, &lt;span&gt;Env&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; [&lt;span&gt;bytecode&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;, &lt;span&gt;pc&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;, &lt;span&gt;a&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;, &lt;span&gt;r0&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;, &lt;span&gt;r1&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;, &lt;span&gt;r2&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;],
        &lt;span&gt;do_trace&lt;/span&gt;(&lt;span&gt;bytecode_loop&lt;/span&gt;, &lt;span&gt;Env&lt;/span&gt;).
&lt;span&gt;trace&lt;/span&gt;
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;,[&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;],[],&lt;span&gt;bytecode_loop_promote_bytecode&lt;/span&gt;)
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,[],&lt;span&gt;bytecode_loop_promote_pc&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;,&lt;span&gt;readlist&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;),&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;))
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;add&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;1&lt;/span&gt;))
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;jump_if_a&lt;/span&gt;))
  &lt;span&gt;guard_false&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;op_jump_if_a&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;mov_a_r0&lt;/span&gt;))
  &lt;span&gt;guard_false&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;op_mov_a_r0&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;mov_a_r1&lt;/span&gt;))
  &lt;span&gt;guard_false&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;op_mov_a_r1&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;mov_a_r2&lt;/span&gt;))
  &lt;span&gt;guard_false&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;op_mov_a_r2&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;mov_r0_a&lt;/span&gt;))
  &lt;span&gt;guard_true&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;not_mov_r0_a&lt;/span&gt;)
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;))
  &lt;span&gt;loop&lt;/span&gt;

&lt;span&gt;opttrace&lt;/span&gt;
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;,[&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;],[],&lt;span&gt;bytecode_loop_promote_bytecode&lt;/span&gt;)
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,[&lt;span&gt;bytecode&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;[&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;]],&lt;span&gt;bytecode_loop_promote_pc&lt;/span&gt;)
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;const&lt;/span&gt;([&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;]))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;3&lt;/span&gt;))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;mov_r0_a&lt;/span&gt;))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;1&lt;/span&gt;))
  &lt;span&gt;loop&lt;/span&gt;

&lt;span&gt;256&lt;/span&gt;
&lt;span&gt;B&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; [&lt;span&gt;mov_a_r0&lt;/span&gt;, &lt;span&gt;mov_a_r1&lt;/span&gt;, &lt;span&gt;mov_r0_a&lt;/span&gt;, &lt;span&gt;decr_a&lt;/span&gt;, &lt;span&gt;mov_a_r0&lt;/span&gt;, &lt;span&gt;mov_r2_a&lt;/span&gt;, &lt;span&gt;add_r1_to_a&lt;/span&gt;, &lt;span&gt;mov_a_r2&lt;/span&gt;, &lt;span&gt;mov_r0_a&lt;/span&gt;|...],
&lt;span&gt;A&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;16&lt;/span&gt;,
&lt;span&gt;Env&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; [&lt;span&gt;bytecode&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;[&lt;span&gt;mov_a_r0&lt;/span&gt;, &lt;span&gt;mov_a_r1&lt;/span&gt;, &lt;span&gt;mov_r0_a&lt;/span&gt;, &lt;span&gt;decr_a&lt;/span&gt;, &lt;span&gt;mov_a_r0&lt;/span&gt;, &lt;span&gt;mov_r2_a&lt;/span&gt;, &lt;span&gt;add_r1_to_a&lt;/span&gt;|...], &lt;span&gt;pc&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;, &lt;span&gt;a&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;, &lt;span&gt;r0&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;, &lt;span&gt;r1&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;, &lt;span&gt;r2&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;]
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These traces are very short. They start with promoting the &lt;tt class=&quot;docutils literal&quot;&gt;bytecode&lt;/tt&gt; and the
&lt;tt class=&quot;docutils literal&quot;&gt;pc&lt;/tt&gt;, followed by the execution of the opcode &lt;tt class=&quot;docutils literal&quot;&gt;mov_r0_a&lt;/tt&gt;, which is the
one at position &lt;tt class=&quot;docutils literal&quot;&gt;2&lt;/tt&gt; in the given bytecode. Then they increment the &lt;tt class=&quot;docutils literal&quot;&gt;pc&lt;/tt&gt; and
loop back to the beginning. Looking at the optimized trace, it is clear that the
trace is essentially useless. It will run only for one iteration, because in the
second iteration the &lt;tt class=&quot;docutils literal&quot;&gt;pc&lt;/tt&gt; is &lt;tt class=&quot;docutils literal&quot;&gt;3&lt;/tt&gt;, thus the &lt;tt class=&quot;docutils literal&quot;&gt;guard_value&lt;/tt&gt; at the beginning
will fail.&lt;/p&gt;
&lt;p&gt;This problem can be solved by tracing more than just one iteration of the
bytecode dispatch loop, which is called meta-tracing. To get this behaviour, in
this simple example it is enough to start (and thus end) tracing at a different
label, &lt;tt class=&quot;docutils literal&quot;&gt;op_jump_if_a_jump&lt;/tt&gt;. This label is hit when the interpreter executes a
&lt;tt class=&quot;docutils literal&quot;&gt;jump_if_a&lt;/tt&gt; bytecode and the jump is taken. In a loop on the level of the
executed bytecode program there is one such jump. Thus tracing from this label,
a full loop in the bytecode program is traced, containing potentially many
iterations of the bytecode dispatch loop in the control flow graph language.&lt;/p&gt;
&lt;p&gt;Doing that yields the following:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;?-&lt;/span&gt; &lt;span&gt;bytecode_square&lt;/span&gt;(&lt;span&gt;B&lt;/span&gt;),
        &lt;span&gt;A&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;16&lt;/span&gt;, &lt;span&gt;Env&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; [&lt;span&gt;bytecode&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;B&lt;/span&gt;, &lt;span&gt;pc&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;11&lt;/span&gt;, &lt;span&gt;a&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;, &lt;span&gt;r0&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;, &lt;span&gt;r1&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;, &lt;span&gt;r2&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;, &lt;span&gt;target&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;],
        &lt;span&gt;do_trace&lt;/span&gt;(&lt;span&gt;op_jump_if_a_jump&lt;/span&gt;, &lt;span&gt;Env&lt;/span&gt;).
&lt;span&gt;trace&lt;/span&gt;
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;target&lt;/span&gt;))
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;,[&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;],[],&lt;span&gt;bytecode_loop&lt;/span&gt;)
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;,[&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;],[],&lt;span&gt;bytecode_loop_promote_bytecode&lt;/span&gt;)
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,[],&lt;span&gt;bytecode_loop_promote_pc&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;,&lt;span&gt;readlist&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;),&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;))
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;add&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;1&lt;/span&gt;))
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;jump_if_a&lt;/span&gt;))
  &lt;span&gt;guard_false&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;op_jump_if_a&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;mov_a_r0&lt;/span&gt;))
  &lt;span&gt;guard_false&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;op_mov_a_r0&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;mov_a_r1&lt;/span&gt;))
  &lt;span&gt;guard_false&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;op_mov_a_r1&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;mov_a_r2&lt;/span&gt;))
  &lt;span&gt;guard_false&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;op_mov_a_r2&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;mov_r0_a&lt;/span&gt;))
  &lt;span&gt;guard_true&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;not_mov_r0_a&lt;/span&gt;)
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;))
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;,[&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;],[],&lt;span&gt;bytecode_loop_promote_bytecode&lt;/span&gt;)
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;3&lt;/span&gt;,[],&lt;span&gt;bytecode_loop_promote_pc&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;,&lt;span&gt;readlist&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;),&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;))
  ...
  &lt;span&gt;lots&lt;/span&gt; &lt;span&gt;of&lt;/span&gt; &lt;span&gt;operations&lt;/span&gt; &lt;span&gt;ommitted&lt;/span&gt;
  ...
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;,[&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;],[],&lt;span&gt;bytecode_loop_promote_bytecode&lt;/span&gt;)
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;9&lt;/span&gt;,[],&lt;span&gt;bytecode_loop_promote_pc&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;,&lt;span&gt;readlist&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;),&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;))
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;add&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;1&lt;/span&gt;))
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;jump_if_a&lt;/span&gt;))
  &lt;span&gt;guard_true&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;not_jump_if_a&lt;/span&gt;)
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;0&lt;/span&gt;))
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;target&lt;/span&gt;,&lt;span&gt;readlist&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;),&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;))
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;add&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;1&lt;/span&gt;))
  &lt;span&gt;guard_false&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[],&lt;span&gt;bytecode_loop&lt;/span&gt;)
  &lt;span&gt;loop&lt;/span&gt;

&lt;span&gt;opttrace&lt;/span&gt;
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;target&lt;/span&gt;))
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;,[&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;],[],&lt;span&gt;bytecode_loop&lt;/span&gt;)
  &lt;span&gt;guard_value&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,[&lt;span&gt;bytecode&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;[&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;]],&lt;span&gt;bytecode_loop_promote_pc&lt;/span&gt;)
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;))
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;,&lt;span&gt;sub&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;1&lt;/span&gt;))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r2&lt;/span&gt;))
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;,&lt;span&gt;add&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;),&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r1&lt;/span&gt;))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;r2&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;r0&lt;/span&gt;))
  &lt;span&gt;op2&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;eq&lt;/span&gt;,&lt;span&gt;var&lt;/span&gt;(&lt;span&gt;a&lt;/span&gt;),&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;0&lt;/span&gt;))
  &lt;span&gt;guard_false&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,[&lt;span&gt;bytecode&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;[&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;],&lt;span&gt;pc&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;11&lt;/span&gt;,&lt;span&gt;opcode&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;target&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;],&lt;span&gt;bytecode_loop&lt;/span&gt;)
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;bytecode&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;const&lt;/span&gt;([&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_a_r1&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;decr_a&lt;/span&gt;,&lt;span&gt;mov_a_r0&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;add_r1_to_a&lt;/span&gt;,&lt;span&gt;mov_a_r2&lt;/span&gt;,&lt;span&gt;mov_r0_a&lt;/span&gt;,&lt;span&gt;jump_if_a&lt;/span&gt;,&lt;span&gt;2&lt;/span&gt;,&lt;span&gt;mov_r2_a&lt;/span&gt;,&lt;span&gt;return_a&lt;/span&gt;]))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;pc&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;11&lt;/span&gt;))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;opcode&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;jump_if_a&lt;/span&gt;))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;target&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;2&lt;/span&gt;))
  &lt;span&gt;op1&lt;/span&gt;(&lt;span&gt;c&lt;/span&gt;,&lt;span&gt;same&lt;/span&gt;,&lt;span&gt;const&lt;/span&gt;(&lt;span&gt;0&lt;/span&gt;))
  &lt;span&gt;loop&lt;/span&gt;

&lt;span&gt;256&lt;/span&gt;
&lt;span&gt;B&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; [&lt;span&gt;mov_a_r0&lt;/span&gt;, &lt;span&gt;mov_a_r1&lt;/span&gt;, &lt;span&gt;mov_r0_a&lt;/span&gt;, &lt;span&gt;decr_a&lt;/span&gt;, &lt;span&gt;mov_a_r0&lt;/span&gt;, &lt;span&gt;mov_r2_a&lt;/span&gt;, &lt;span&gt;add_r1_to_a&lt;/span&gt;, &lt;span&gt;mov_a_r2&lt;/span&gt;, &lt;span&gt;mov_r0_a&lt;/span&gt;|...],
&lt;span&gt;A&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;16&lt;/span&gt;,
&lt;span&gt;Env&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; [&lt;span&gt;bytecode&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;[&lt;span&gt;mov_a_r0&lt;/span&gt;, &lt;span&gt;mov_a_r1&lt;/span&gt;, &lt;span&gt;mov_r0_a&lt;/span&gt;, &lt;span&gt;decr_a&lt;/span&gt;, &lt;span&gt;mov_a_r0&lt;/span&gt;, &lt;span&gt;mov_r2_a&lt;/span&gt;, &lt;span&gt;add_r1_to_a&lt;/span&gt;|...], &lt;span&gt;pc&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;11&lt;/span&gt;, &lt;span&gt;a&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;, &lt;span&gt;r0&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;, &lt;span&gt;r1&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;, &lt;span&gt;r2&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;, &lt;span&gt;target&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;] .
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That looks better. The trace corresponds to the interpreter running all the
bytecodes in the loop of the squaring function in the example bytecode above.
The optimized code starts with
two guards (checking that the &lt;tt class=&quot;docutils literal&quot;&gt;bytecode&lt;/tt&gt; is still the one for the squaring
function, checking that the &lt;tt class=&quot;docutils literal&quot;&gt;pc&lt;/tt&gt; is &lt;tt class=&quot;docutils literal&quot;&gt;2&lt;/tt&gt;) and then only does the operations
that actually do the computation. No bytecode dispatching is performed, thus the
interpretation overhead is fully removed, apart from the two &lt;tt class=&quot;docutils literal&quot;&gt;guard_value&lt;/tt&gt;
operations at the beginning.&lt;/p&gt;
&lt;p&gt;Many of the assignments in the trace are superfluous, e.g. all the copying back
and forth between registers &lt;tt class=&quot;docutils literal&quot;&gt;r1&lt;/tt&gt;, &lt;tt class=&quot;docutils literal&quot;&gt;r1&lt;/tt&gt;, &lt;tt class=&quot;docutils literal&quot;&gt;r2&lt;/tt&gt; and accumulator &lt;tt class=&quot;docutils literal&quot;&gt;a&lt;/tt&gt;. This
could be easily solved by an even more intelligent optimization utilizing &lt;a class=&quot;reference external&quot; href=&quot;http://en.wikipedia.org/wiki/Static_single_assignment_form&quot;&gt;SSA
form&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusion About the Interpreter&lt;/h2&gt;
&lt;p&gt;Both partial evaluation and meta-tracing can be used to transform the example
bytecode computing a square into a form that shows the essential computation
that is going on, without the interpretation overhead. The naive partial evaluator
produces lots of extra blocks that just jump around, which could be solved with
a post-processing step. The tracer by itself produces uselessly short traces,
but with a simple trick of starting the trace at a different point the results
become a lot better.&lt;/p&gt;
&lt;p&gt;In a real meta-tracing system, the meta-tracer would need a way for the author
of the interpreter
to mark which bytecode corresponds to a backward jump. It would also need better
integration with the interpreter to start tracing automatically, as well as
cache the traces. Additionally, it would have to deal better with guards that fail a
lot, attaching new traces to the failing guards. However, all that is &amp;quot;just&amp;quot;
engineering on top of the ideas presented in this series of blog posts.&lt;/p&gt;
&lt;h2&gt;High-Level Conclusion&lt;/h2&gt;
&lt;p&gt;Some concluding high-level thoughts about the similarities of tracing and
partial evaluation: Tracing and partial evaluation try to tackle a similar
problem, that of automatically reducing the interpreter overhead, their
approaches are slightly different though.&lt;/p&gt;
&lt;p&gt;Tracing is very close to normal evaluation, only keeping some extra information
in the process. But then, the optimizer that is used in a tracer
is again very similar in structure to a partial evaluator. The task of the
optimizer is much simpler though, because it does not need to deal with control
flow at all, just a linear list of operations.&lt;/p&gt;
&lt;p&gt;So in a sense tracing is taking those parts of partial evaluation that work (the
&amp;quot;just evaluate those things that you can, and leave the others&amp;quot;) and replacing
the parts that don't (controlling unfolding) by a much more pragmatic mechanism.
That mechanism observes actual execution runs of the program to choose control
flow paths that are typical. At the same time, the tracer's focus is on loops,
because they are where most programs spend significant amounts of time.&lt;/p&gt;
&lt;p&gt;Another point of view of tracing is that it is a form of partial evaluation that
replaces the control components of a partial evaluator with an oracle (the
actual execution runs) that provide the information which paths to look at.&lt;/p&gt;
&lt;p&gt;Already in the quite trivial interpreter here the effects of this are visible.
The simple partial evaluator over-specializes the loop and produces two
identical versions of it, that aren't different. The tracer doesn't, and it
also generates only code for the loop itself, not for the initialization
opcodes.&lt;/p&gt;
&lt;p&gt;That's it for this series. To those that made it, thanks for following along.
Also thanks to Samuele and Sven, who consistently gave me good feedback on the
posts before I put them here.&lt;/p&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;img width=&quot;1&quot; height=&quot;1&quot; src=&quot;https://blogger.googleusercontent.com/tracker/3971202189709462152-6139699450091061040?l=morepypy.blogspot.com&quot; alt=&quot;&quot; /&gt;&lt;/div&gt;&lt;img src=&quot;http://feeds.feedburner.com/~r/PyPyStatusBlog/~4/sautdC5jeto&quot; height=&quot;1&quot; width=&quot;1&quot; /&gt;</description>
	<pubDate>Mon, 13 Feb 2012 15:50:31 +0000</pubDate>
</item>
<item>
	<title>Matt Harrison: Amazon KDP Non-Fiction Week 2 Update</title>
	<guid>http://hairysun.com/blog/2012/02/13/amazon-kdp-week-2-update/</guid>
	<link>http://hairysun.com/blog/2012/02/13/amazon-kdp-week-2-update/</link>
	<description>&lt;p&gt;&lt;img class=&quot;center&quot; src=&quot;http://hairysun.com/images/kindle3-dec.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I am two weeks into &lt;a href=&quot;http://hairysun.com/blog/2012/01/30/amazon-kdp-select-for-non-fiction-technical-books/&quot;&gt;my Amazon KDP non-fiction experiment&lt;/a&gt;. &lt;a href=&quot;http://hairysun.com/books/decorators/&quot;&gt;Guide to: Learning Python Decorators&lt;/a&gt; is currently &lt;a href=&quot;http://www.amazon.com/gp/bestsellers/books/285856/?ie=UTF8&amp;tag=hairysuncom-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=390957&quot;&gt;#15 on the Python list&lt;/a&gt; as I write this, but was up at 5 during the week. It is aso &lt;a href=&quot;http://www.amazon.com/gp/new-releases/books/285856/?ie=UTF8&amp;tag=hairysuncom-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=390957&quot;&gt;#1 on the Python &amp;#8220;Hot New Releases&amp;#8221;&lt;/a&gt;, which surprises me because #2 is a really strong title. Sales of both of my books have been slow and steady. I heard that the average &amp;#8220;indie&amp;#8221; author only sells 4 books/month. I&amp;#8217;m happy to report that I&amp;#8217;m slightly better than that and I will be receiving a check from Amazon this month ($100+ in sales).&lt;/p&gt;

&lt;p&gt;What else have I done this week? I have wondered about Amazon&amp;#8217;s lack of existence in BRIC (Brazil, Russia, India and China). When I had my own store front, I was able to sell to a few individuals from some of those countries. Now I am not because Amazon has no presence there. Again this is probably not something Indie fiction writers care about (with perhaps the exception of India) — I assume fiction is somewhat language dependent. But many programmers know English, so presumably I am losing some sales. How big would they be? I am not sure, but I have received at least one request from someone who claimed they did not have Kindle reader access. Currently my non-US sales are less than 10% of US sales. I am not sure if that is a function of my marketing, or how strong the Amazon presence is in those countries (UK, DE, ES, IT, FR), or some combination of the two.&lt;/p&gt;

&lt;p&gt;I also &lt;a href=&quot;https://authorcentral.amazon.com/gp/landing&quot;&gt;signed up for Amazon Author Central&lt;/a&gt;. Perhaps this will help with SEO, I am not sure, but I now have an &lt;a href=&quot;http://www.amazon.com/gp/entity/Matt-Harrison/B0077BQLH6/?ie=UTF8&amp;refinementId=618073011&amp;tag=hairysuncom-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=390957&quot;&gt;author page&lt;/a&gt;, which also aggregates this blog and my &lt;a href=&quot;http://twitter.com/__mharrison__&quot;&gt;tweetstream&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While at the Utah Python group this week, the first presenter actually mentioned my decorator book in his talk. When the meeting ended, an attendee informed me that he thought my book was pretty good (which he had purchased and was reading during the second presentation). Also he gave me some more feedback, which is always nice.&lt;/p&gt;

&lt;p&gt;I also spent some time looking into pbook generation. My calculation is around 4% of people would prefer dead tree books (very unscientific, consists of requests divided by current sales at some point in time). KDP only requires exclusive digital rights to your sales, not physical, so this is a very real possibility. But, my current pdf generation has issues and I starting learning LaTex to solve those. I hope to have some sort of dead tree versions released soon. I&amp;#8217;m thinking about using CreateSpace, but would be open to using other POD services. If you have experience with POD feel free to drop me some notes.&lt;/p&gt;

&lt;p&gt;My book was &lt;a href=&quot;http://www.thebookdesigner.com/2012/02/ebook-cover-design-awards-january-2012/&quot;&gt;submitted to the January 2012 Ebook Cover Design Awards&lt;/a&gt;, which was released this week. I was hoping to get some feedback on my cover, but did not. I interpret that response as an indication of the “blah”-ness of my cover. Not sufficiently interesting to warrant any praise, nor blatantly bad enough to expose the horrible design elements.&lt;/p&gt;

&lt;p&gt;Finally, a huge advantage to KDP, is I can easily push updates and Amazon handles everything else. A disadvantage is anonymity of purchases. With sales from my site, I had emails for all purchases and could interact with buyers, but pushing updates was a bit more of a pain. Some food for thought if you are considering one or the other. I really like to think that ebooks are somehow “alive” and that I can incorporate reader feedback very quickly and actually push it out, though this is not something that “real” publishers seem to be doing yet. I&amp;#8217;m thinking that I might stay on KDP with my more expensive/longer &lt;a href=&quot;http://hairysun.com/books/tread&quot;&gt;Treading on Python&lt;/a&gt; which receives a higher percentage of &amp;#8220;rentals&amp;#8221;, and make distribution of smaller ebooks more widely available — Kobo, my own site, and perhaps BN again.&lt;/p&gt;</description>
	<pubDate>Mon, 13 Feb 2012 13:03:00 +0000</pubDate>
</item>

</channel>
</rss>

