<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Gábor's blog</title>
  <link rel="alternate" type="text/html" href="http://www.nekomancer.net/blog/archives/python-web-app-using-generators"/>
  <link rel="self" type="application/atom+xml" href="http://www.nekomancer.net/node/153/atom/feed"/>
  <id>http://www.nekomancer.net/node/153/atom/feed</id>
  <updated>2008-06-27T03:41:12-05:00</updated>
  <entry>
    <title>python web-application using generators</title>
    <link rel="alternate" type="text/html" href="http://www.nekomancer.net/blog/archives/python-web-app-using-generators" />
    <id>http://www.nekomancer.net/blog/archives/python-web-app-using-generators</id>
    <published>2008-03-01T17:16:16-06:00</published>
    <updated>2008-06-27T03:41:12-05:00</updated>
    <author>
      <name>gabor</name>
    </author>
    <category term="python" />
    <category term="programming" />
    <summary type="html"><![CDATA[<p>Probably many of you have heard already about <a href="http://www.seaside.st/">Seaside</a>. It&#8217;s a smalltalk web framework, where you can write a web-app in a linear style:</p>

<p>let&#8217;s say you want to create a web-app which:</p>

<ul>
<li>shows a form to the user, where he can enter a number and submit it</li>
<li>then you show him a second form, where the user can enter a second number and submit it</li>
<li>then you show the user a page which displays the sum of those 2 submitted numbers</li>
</ul>
    ]]></summary>
    <content type="html"><![CDATA[<p>Probably many of you have heard already about <a href="http://www.seaside.st/">Seaside</a>. It&#8217;s a smalltalk web framework, where you can write a web-app in a linear style:</p>

<p>let&#8217;s say you want to create a web-app which:</p>

<ul>
<li>shows a form to the user, where he can enter a number and submit it</li>
<li>then you show him a second form, where the user can enter a second number and submit it</li>
<li>then you show the user a page which displays the sum of those 2 submitted numbers
<!--break-->
in Seaside, you can implement it in something like this:
(pseudocode)</li>
</ul>

<div class="geshifilter"><pre class="geshifilter-python">first_num = get_number<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
second_num = get_number<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
display<span style="color: black;">&#40;</span>first_num + second_num<span style="color: black;">&#41;</span></pre></div>

<p>my language of choice is python, so i was curious if it&#8217;s possible to achieve something similar in that language. seside uses <a href="http://en.wikipedia.org/wiki/Continuation">continuations</a> to achieve this, so i turned to <a href="http://docs.python.org/ref/yield.html">python generators</a>. they allowed me to write this:</p>

<div class="geshifilter"><pre class="geshifilter-python"><span style="color: #ff7700;font-weight:bold;">def</span> sum_two_numbers<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    first_num = <span style="color: #ff7700;font-weight:bold;">yield</span> InputPage<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;enter first number:&quot;</span><span style="color: black;">&#41;</span>
    second_num = <span style="color: #ff7700;font-weight:bold;">yield</span> InputPage<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;enter second number:&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #008000;">sum</span> = <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>first_num<span style="color: black;">&#41;</span> + <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>second_num<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">yield</span> TextPage<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;the sum isresult is: %s&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: #008000;">sum</span><span style="color: black;">&#41;</span></pre></div>

<p>the full code is below, but first some notes about it:</p>

<ul>
<li>it requires python 2.5 or higher, because i use the <a href="http://docs.python.org/whatsnew/pep-342.html">&#8220;advanced&#8221; version of yield</a>, which appeared in python2.5</li>
<li>this is only proof-of-concept code, and i know that it uses global-variables, ugly names, get-where-it-should-do-post etc.</li>
<li>i know Seaside does much much more (backbutton-support etc.)</li>
</ul>

<p>the code:</p>

<div class="geshifilter"><pre class="geshifilter-python"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python2.5</span>
<span style="color: #ff7700;font-weight:bold;">from</span> wsgiref.<span style="color: black;">simple_server</span> <span style="color: #ff7700;font-weight:bold;">import</span> make_server
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">cgi</span> <span style="color: #ff7700;font-weight:bold;">import</span> parse_qs
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> TextPage<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,text<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">text</span> = text
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> get_response_content<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">'&lt;html&gt;&lt;body&gt;%s&lt;/body&gt;&lt;/html&gt;'</span> <span style="color: #66cc66;">%</span> <span style="color: #008000;">self</span>.<span style="color: black;">text</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> get_request_data<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>,environ<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">None</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> InputPage<span style="color: black;">&#40;</span>TextPage<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> get_response_content<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;&lt;html&gt;&lt;body&gt;%s
            &lt;form method=&quot;</span>get<span style="color: #483d8b;">&quot; action=&quot;</span>.<span style="color: #483d8b;">&quot;&gt;
            &lt;input type=&quot;</span>text<span style="color: #483d8b;">&quot; name=&quot;</span>data<span style="color: #483d8b;">&quot; value=&quot;</span><span style="color: #483d8b;">&quot;/&gt;
            &lt;/form&gt;
            &lt;/body&gt;&lt;/html&gt;&quot;</span><span style="color: #483d8b;">&quot;&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: #008000;">self</span>.<span style="color: black;">text</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> get_request_data<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, environ<span style="color: black;">&#41;</span>:
        get_req_dict = parse_qs<span style="color: black;">&#40;</span>environ<span style="color: black;">&#91;</span><span style="color: #483d8b;">'QUERY_STRING'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> get_req_dict<span style="color: black;">&#91;</span><span style="color: #483d8b;">'data'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> sum_two_numbers<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    first_num = <span style="color: #ff7700;font-weight:bold;">yield</span> InputPage<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;enter first number:&quot;</span><span style="color: black;">&#41;</span>
    second_num = <span style="color: #ff7700;font-weight:bold;">yield</span> InputPage<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;enter second number:&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #008000;">sum</span> = <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>first_num<span style="color: black;">&#41;</span> + <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>second_num<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">yield</span> TextPage<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;the sum isresult is: %s&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: #008000;">sum</span><span style="color: black;">&#41;</span>
&nbsp;
s = sum_two_numbers<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
cur_item = <span style="color: #008000;">None</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> simple_app<span style="color: black;">&#40;</span>environ, start_response<span style="color: black;">&#41;</span>:
    status = <span style="color: #483d8b;">'200 OK'</span>
    response_headers = <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Content-type'</span>,<span style="color: #483d8b;">'text/html'</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
    start_response<span style="color: black;">&#40;</span>status, response_headers<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">global</span> cur_item
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> cur_item:
        cur_item = s.<span style="color: black;">next</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        cur_item = s.<span style="color: black;">send</span><span style="color: black;">&#40;</span>cur_item.<span style="color: black;">get_request_data</span><span style="color: black;">&#40;</span>environ<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#91;</span>cur_item.<span style="color: black;">get_response_content</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>
&nbsp;
&nbsp;
httpd = make_server<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>, <span style="color: #ff4500;">8000</span>, simple_app<span style="color: black;">&#41;</span>
httpd.<span style="color: black;">serve_forever</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div>

<p>i did a quick google-check about this topic (&#8220;python web framework continuations&#8221;), and only found <a href="http://twistedmatrix.com/pipermail/twisted-web/2004-November/000863.html">Nevow with Wolf</a>, which uses a less-elegant approach, probably because when it was implemented, python2.5 was not yet available. if anyone knows about other python web-frameworks that use generators, leave me a comment.</p>
    ]]></content>
  </entry>
</feed>
