<?xml version="1.0" encoding="UTF-8"?>
<feed
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:thr="http://purl.org/syndication/thread/1.0"
  xml:lang="en"
   >
  <title type="text">What's Chris Doing?</title>
  <subtitle type="text">Programming, photography, music and life</subtitle>

  <updated>2015-02-22T15:14:41Z</updated>
  <generator uri="http://blogofile.com/">Blogofile</generator>

  <link rel="alternate" type="text/html" href="http://whatschrisdoing.com/blog/" />
  <id>http://whatschrisdoing.com/blog//feed/atom/</id>
  <link rel="self" type="application/atom+xml" href="http://whatschrisdoing.com/blog//feed/atom/" />
  <entry>
    <author>
      <name></name>
      <uri>http://whatschrisdoing.com/blog/</uri>
    </author>
    <title type="html"><![CDATA[Making HTTPS Requests secure in Python]]></title>
    <link rel="alternate" type="text/html" href="http://whatschrisdoing.com/blog/2011/10/30/making-https-requests-secure-in-python/" />
    <id>http://whatschrisdoing.com/blog/2011/10/30/making-https-requests-secure-in-python/</id>
    <updated>2011-10-30T17:07:19Z</updated>
    <published>2011-10-30T17:07:19Z</published>
    <category scheme="http://whatschrisdoing.com/blog/" term="Programming" />
    <summary type="html"><![CDATA[Making HTTPS Requests secure in Python]]></summary>
    <content type="html" xml:base="http://whatschrisdoing.com/blog/2011/10/30/making-https-requests-secure-in-python/"><![CDATA[<div class="document">
<p>Python 2.7 does not automatically validate certificates on HTTPS requests. The following seems to be the cleanest, though not necessarily fully secure method to get there.</p>
<p>This will work with:</p>
<ul class="simple">
<li><a class="reference external" href="http://docs.python.org/library/httplib.html">httplib</a></li>
<li><a class="reference external" href="http://docs.python.org/library/urllib.html">urllib</a></li>
<li><a class="reference external" href="http://docs.python.org/library/urllib2.html">urlib2</a></li>
<li><a class="reference external" href="http://python-requests.org/">requests</a></li>
</ul>
<p>It may work with other libs that depend on the HTTPSConnection class from httplib in the Python Standard Library.</p>


<div class="pygments_murphy"><pre><span class="kn">import</span> <span class="nn">httplib</span>
<span class="kn">import</span> <span class="nn">socket</span>
<span class="kn">import</span> <span class="nn">ssl</span>
<span class="kn">from</span> <span class="nn">backports.ssl_match_hostname</span> <span class="kn">import</span> <span class="n">match_hostname</span>

<span class="k">def</span> <span class="nf">install_validating_https</span><span class="p">(</span><span class="n">cert_file</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">validating_connect</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s">&quot;Connect to a host on a given (SSL) port.&quot;</span>

        <span class="n">sock</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">create_connection</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">host</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">port</span><span class="p">),</span>
                                        <span class="bp">self</span><span class="o">.</span><span class="n">timeout</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">source_address</span><span class="p">)</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_tunnel_host</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">sock</span> <span class="o">=</span> <span class="n">sock</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_tunnel</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">sock</span> <span class="o">=</span> <span class="n">ssl</span><span class="o">.</span><span class="n">wrap_socket</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">key_file</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">cert_file</span><span class="p">,</span> <span class="n">cert_reqs</span><span class="o">=</span><span class="n">ssl</span><span class="o">.</span><span class="n">CERT_REQUIRED</span><span class="p">,</span> <span class="n">ca_certs</span><span class="o">=</span><span class="n">cert_file</span><span class="p">)</span>
        <span class="n">match_hostname</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sock</span><span class="o">.</span><span class="n">getpeercert</span><span class="p">(),</span> <span class="bp">self</span><span class="o">.</span><span class="n">host</span><span class="p">)</span>



    <span class="n">httplib</span><span class="o">.</span><span class="n">HTTPSConnection</span><span class="o">.</span><span class="n">connect</span> <span class="o">=</span> <span class="n">validating_connect</span>
</pre></div>



<p>Okay, that's the basics. backports.ssl_match_hostname is available in pypi, the rest is stdlib. This should work with 2.6+, for &lt; 2.6 you'll want to get the ssl library from pypi (I don't know the implications for the HTTPSConnection lib for anything other than 2.7).</p>
<p>Somewhere in your app, call <tt class="docutils literal">install_validating_https</tt> and pass it the path to your root ca collection file. Oh, wait, what's that? Well it probably would be a pem encoding of the <a class="reference external" href="https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt">Mozilla NSS certdata.txt</a>. The pem encoding can be done with the <a class="reference external" href="http://www.heikkitoivonen.net/blog/2008/09/30/root-certificates-for-python-programs-using-python/">certdata2pem.py script that comes with M2Crypto</a> or you can get a <a class="reference external" href="http://curl.haxx.se/ca/cacert.pem">pre-built one</a> from the <a class="reference external" href="http://curl.haxx.se/">curl project</a> (depending on your level of paranoia since you can't download the curl version over https).</p>
<p>Much of the initial info that went into my final solution came from <a class="reference external" href="http://wiki.python.org/moin/SSL">the SSL Topic on the Python Wiki</a> and <a class="reference external" href="http://stackoverflow.com/questions/1087227/validate-ssl-certificates-with-python">the &quot;How to validate SSL Certificates with Python&quot; question on Stack Overflow</a> with a sprinkling of <a class="reference external" href="http://bugs.python.org/">Python bug reports</a>.</p>
</div>
]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://whatschrisdoing.com/blog/</uri>
    </author>
    <title type="html"><![CDATA[Notes on localization and jQueryUI Datepicker.]]></title>
    <link rel="alternate" type="text/html" href="http://whatschrisdoing.com/blog/2010/06/04/notes-on-localization-and-jqueryui-datepicker/" />
    <id>http://whatschrisdoing.com/blog/2010/06/04/notes-on-localization-and-jqueryui-datepicker/</id>
    <updated>2010-06-04T10:24:50Z</updated>
    <published>2010-06-04T10:24:50Z</published>
    <category scheme="http://whatschrisdoing.com/blog/" term="Programming" />
    <summary type="html"><![CDATA[Notes on localization and jQueryUI Datepicker.]]></summary>
    <content type="html" xml:base="http://whatschrisdoing.com/blog/2010/06/04/notes-on-localization-and-jqueryui-datepicker/"><![CDATA[<div class="document">
<p>The current <a class="reference external" href="http://jqueryui.com/demos/datepicker/">documentation for the jQuery UI Datepicker</a> control and localization are a little bit sparse. The overview tab has a blurb about the the <tt class="docutils literal">$.datepicker.regional</tt> object containing a set of localizations indexed by locale code ('fr', 'en-GB', etc) and that those locales return an object with the attributes that provide a basis for the options object to be provided to the <tt class="docutils literal"><span class="pre">$('selector').datepicker()</span></tt> function, then there is a link to the localization files in Subversion. Lets be clear about how the <tt class="docutils literal">$.datepicker.regional</tt> object is populated and how to use it:</p>
<ol class="arabic simple">
<li>You can get all of the locales as one big file from the Google CDN as: <a class="reference external" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/i18n/jquery-ui-i18n.min.js">http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/i18n/jquery-ui-i18n.min.js</a></li>
<li>Even though you can, you probably should not include the giant file of all locales from the Google CDN because it will add 9.5KB compressed or 50KB uncompressed. Include the locales you need in a combined minified file for you site (perhaps combined with the rest of the scripts for your site)</li>
<li>The <tt class="docutils literal">$.datepicker.regional</tt> object will not fall back to a less specific locale, i.e. if you give it fr-CA, it will not fall back to fr if it does not have it, you would have to come up with that logic yourself.</li>
</ol>
<p>Points 1 and 2 can be improved by adding the ability to select the locales in the <a class="reference external" href="http://jqueryui.com/download">jQuery UI Download builder tool</a>. Point 3 can be improved by adding a <tt class="docutils literal">$.datepicker.getregion()</tt> function that returns a valid object based on the normal locale parsing rules.</p>
<p>The function might look like:</p>


<div class="pygments_murphy"><pre><span class="nx">$</span><span class="p">.</span><span class="nx">datepicker</span><span class="p">.</span><span class="nx">getregion</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">region</span><span class="p">)</span> <span class="p">{</span>
  <span class="kd">var</span> <span class="nx">retval</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">datepicker</span><span class="p">.</span><span class="nx">regional</span><span class="p">[</span><span class="nx">region</span><span class="p">];</span>
  <span class="k">if</span> <span class="p">(</span><span class="nx">retval</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">retval</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="nx">region</span> <span class="o">=</span> <span class="nx">region</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">);</span>
  <span class="nx">retval</span> <span class="o">=</span> <span class="nx">$</span><span class="p">.</span><span class="nx">datepicker</span><span class="p">.</span><span class="nx">regional</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
  <span class="k">if</span> <span class="p">(</span><span class="nx">region</span><span class="p">.</span><span class="nx">length</span> <span class="o">==</span> <span class="mi">2</span> <span class="o">&amp;&amp;</span> <span class="nx">retval</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">retval</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="k">return</span> <span class="nx">$</span><span class="p">.</span><span class="nx">datepicker</span><span class="p">.</span><span class="nx">regional</span><span class="p">[</span><span class="s1">&#39;&#39;</span><span class="p">];</span>
<span class="p">}</span>
</pre></div>



</div>
]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://whatschrisdoing.com/blog/</uri>
    </author>
    <title type="html"><![CDATA[ASP.NET MVC and Ionic.Zip]]></title>
    <link rel="alternate" type="text/html" href="http://whatschrisdoing.com/blog/2010/03/22/asp-net-mvc-and-ionic-zip/" />
    <id>http://whatschrisdoing.com/blog/2010/03/22/asp-net-mvc-and-ionic-zip/</id>
    <updated>2010-03-22T10:19:10Z</updated>
    <published>2010-03-22T10:19:10Z</published>
    <category scheme="http://whatschrisdoing.com/blog/" term="Programming" />
    <summary type="html"><![CDATA[ASP.NET MVC and Ionic.Zip]]></summary>
    <content type="html" xml:base="http://whatschrisdoing.com/blog/2010/03/22/asp-net-mvc-and-ionic-zip/"><![CDATA[<div class="document">
<p>I wanted to stream a dynamically generated Zip file in a ASP.NET MVC site. <a class="reference external" href="http://dotnetzip.codeplex.com/">Ionic.Zip</a> looked like the best option for Zip library. The <a class="reference external" href="http://dotnetzip.codeplex.com/wikipage?title=CS-Examples&amp;referringTitle=Examples">Create a downloadable zip within ASP.NET example</a> looked pretty close to what I needed, but I wanted to have a suitable ActionResult class to use in my controller. Here is what I came up with:</p>


<div class="pygments_murphy"><pre>    <span class="c1">/// &lt;summary&gt;</span>
    <span class="c1">/// A content result which can accepts a DotNetZip ZipFile object to write to the output stream</span>
    <span class="c1">/// &lt;/summary&gt;</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">ZipFileResult</span> <span class="p">:</span> <span class="n">ActionResult</span>
    <span class="p">{</span>

        <span class="k">public</span> <span class="n">ZipFile</span> <span class="n">zip</span> <span class="p">{</span><span class="k">get</span><span class="p">;</span><span class="k">set</span><span class="p">;}</span>
        <span class="k">public</span> <span class="kt">string</span> <span class="n">filename</span> <span class="p">{</span><span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;}</span>

        <span class="k">public</span> <span class="nf">ZipFileResult</span><span class="p">(</span><span class="n">ZipFile</span> <span class="n">zip</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">this</span><span class="p">.</span><span class="n">zip</span> <span class="p">=</span> <span class="n">zip</span><span class="p">;</span>
            <span class="k">this</span><span class="p">.</span><span class="n">filename</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">public</span> <span class="nf">ZipFileResult</span><span class="p">(</span><span class="n">ZipFile</span> <span class="n">zip</span><span class="p">,</span> <span class="kt">string</span> <span class="n">filename</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="k">this</span><span class="p">.</span><span class="n">zip</span> <span class="p">=</span> <span class="n">zip</span><span class="p">;</span>
            <span class="k">this</span><span class="p">.</span><span class="n">filename</span> <span class="p">=</span> <span class="n">filename</span><span class="p">;</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">ExecuteResult</span><span class="p">(</span><span class="n">ControllerContext</span> <span class="n">context</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">Response</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">HttpContext</span><span class="p">.</span><span class="n">Response</span><span class="p">;</span>

            <span class="n">Response</span><span class="p">.</span><span class="n">ContentType</span> <span class="p">=</span> <span class="s">&quot;application/zip&quot;</span><span class="p">;</span>
            <span class="n">Response</span><span class="p">.</span><span class="n">AddHeader</span><span class="p">(</span><span class="s">&quot;Content-Disposition&quot;</span><span class="p">,</span> <span class="s">&quot;attachment;&quot;</span> <span class="p">+</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="n">IsNullOrEmpty</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="p">?</span> <span class="s">&quot;&quot;</span> <span class="p">:</span> <span class="s">&quot;filename=&quot;</span> <span class="p">+</span> <span class="n">filename</span><span class="p">));</span>


            <span class="n">zip</span><span class="p">.</span><span class="n">Save</span><span class="p">(</span><span class="n">Response</span><span class="p">.</span><span class="n">OutputStream</span><span class="p">);</span>

            <span class="n">Response</span><span class="p">.</span><span class="n">End</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
</pre></div>



<p>The example noted above becomes:</p>


<div class="pygments_murphy"><pre><span class="k">public</span> <span class="k">class</span> <span class="nc">MyZipFileController</span> <span class="p">:</span> <span class="n">Controller</span>
<span class="p">{</span>

    <span class="k">public</span> <span class="n">ActionResult</span> <span class="nf">Index</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">string</span> <span class="n">ReadmeText</span><span class="p">=</span> <span class="s">&quot;This is a zip file dynamically generated at &quot;</span> <span class="p">+</span> <span class="n">System</span><span class="p">.</span><span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">.</span><span class="n">ToString</span><span class="p">(</span><span class="s">&quot;G&quot;</span><span class="p">);</span>
        <span class="kt">string</span> <span class="n">filename</span> <span class="p">=</span> <span class="n">System</span><span class="p">.</span><span class="n">IO</span><span class="p">.</span><span class="n">Path</span><span class="p">.</span><span class="n">GetFileName</span><span class="p">(</span><span class="n">ListOfFiles</span><span class="p">.</span><span class="n">SelectedItem</span><span class="p">.</span><span class="n">Text</span><span class="p">)</span> <span class="p">+</span> <span class="s">&quot;.zip&quot;</span><span class="p">;</span>

        <span class="n">ZipFile</span> <span class="n">zip</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ZipFile</span><span class="p">();</span>
        <span class="n">zip</span><span class="p">.</span><span class="n">AddFile</span><span class="p">(</span><span class="n">ListOfFiles</span><span class="p">.</span><span class="n">SelectedItem</span><span class="p">.</span><span class="n">Text</span><span class="p">,</span> <span class="s">&quot;files&quot;</span><span class="p">);</span>
        <span class="n">zip</span><span class="p">.</span><span class="n">AddEntry</span><span class="p">(</span><span class="s">&quot;Readme.txt&quot;</span><span class="p">,</span> <span class="s">&quot;&quot;</span><span class="p">,</span> <span class="n">ReadmeText</span><span class="p">);</span>
        <span class="k">return</span> <span class="k">new</span> <span class="nf">ZipFileResult</span><span class="p">(</span><span class="n">zip</span><span class="p">,</span> <span class="n">filename</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></div>



</div>
]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://whatschrisdoing.com/blog/</uri>
    </author>
    <title type="html"><![CDATA[Cross Compiling Python Extensions]]></title>
    <link rel="alternate" type="text/html" href="http://whatschrisdoing.com/blog/2009/10/16/cross-compiling-python-extensions/" />
    <id>http://whatschrisdoing.com/blog/2009/10/16/cross-compiling-python-extensions/</id>
    <updated>2009-10-16T23:07:50Z</updated>
    <published>2009-10-16T23:07:50Z</published>
    <category scheme="http://whatschrisdoing.com/blog/" term="Computers" />
    <category scheme="http://whatschrisdoing.com/blog/" term="Programming" />
    <summary type="html"><![CDATA[Cross Compiling Python Extensions]]></summary>
    <content type="html" xml:base="http://whatschrisdoing.com/blog/2009/10/16/cross-compiling-python-extensions/"><![CDATA[<div class="document">
<p>If you are working with Python in an embedded environment, you will enventually want to build a Python extension with a cross tool chain. These instructions work both with <a class="reference external" href="http://www.openembedded.org/">Open Embedded</a> and <a class="reference external" href="http://www.denx.de/wiki/DULG/ELDK">the DENX ELDK</a>. If you need to go cross compile Python <a class="reference external" href="http://whatschrisdoing.com/blog/2006/10/06/howto-cross-compile-python-25/">2.5</a>, <a class="reference external" href="http://randomsplat.com/id5-cross-compiling-python-for-embedded-linux.html">2.6 or 3.1</a>. ELDK and Open Embedded include a version of Python pre-done for you. You will need a version of Python for the build system that matches your target enviroment.</p>
<p>On the host machine install <a class="reference external" href="http://pypi.python.org/pypi/setuptools">setuptools</a> and <a class="reference external" href="http://pypi.python.org/pypi/distutilscross">distutilscross</a>. If you are using Python 2.6.3 you probably need to also install <a class="reference external" href="http://pypi.python.org/pypi/distribute">distribute</a> which is a replacement for setuptools that also happens to fix a conflict between setuptools 0.6c9 and Python 2.6.3 <em>(There is an update of setuptools coming soon too. See the update below)</em>. If you want to use <a class="reference external" href="http://pypi.python.org/pypi/virtualenv">virtualenv</a> and distribute together, you might need to use <a class="reference external" href="http://pypi.python.org/pypi/virtualenv-distribute">virtualenv-distribute</a>, a fork of virtualenv that uses distribute instead of setuptools.</p>
<p>Distutilscross is a package that uses setuptools to monkey patch an extra parameter, --cross-compile, into the distutils build command. The net result is that you can set your cross compile environment variables, plus PYTHONXCPREFIX and do <tt class="docutils literal">python setup.py build <span class="pre">-x</span></tt> to get your extensions to compile.</p>
<p>Lets take ELDK as an example.</p>


<div class="pygments_murphy"><pre><span class="nv">$ </span><span class="nb">export </span><span class="nv">PYTHONXCPREFIX</span><span class="o">=</span>/opt/eldk/ppc_4xxFP/usr
<span class="nv">$ </span><span class="nb">export </span><span class="nv">CROSS_COMPILE</span><span class="o">=</span>ppc_4xxFP-
<span class="nv">$ </span><span class="nb">export </span><span class="nv">CC</span><span class="o">=</span><span class="s2">&quot;${CROSS_COMPILE}gcc -pthread&quot;</span>
<span class="nv">$ </span><span class="nb">export </span><span class="nv">LDSHARED</span><span class="o">=</span><span class="s2">&quot;${CC} -shared&quot;</span>
<span class="nv">$ </span><span class="nb">export </span><span class="nv">LDFLAGS</span><span class="o">=</span><span class="s2">&quot;-L/opt/eldk/ppc_4xxFP/usr/lib -L/opt/eldk/ppc_4xxFP/lib&quot;</span>
<span class="nv">$ </span>python setup.py build -x bdist_egg --plat-name<span class="o">=</span>linux-ppc
</pre></div>



<p>We always need to define PYTHONXCPREFIX and LDFLAGS. PYTHONXCPREFIX tells the -x (or --cross-compile) where your target built Python is. Mostly it is looking for the options used at build time from $PREFIX/lib/python2.x/config/Makefile. This will also set the compile up to use the target Python's headers. We need to set LDFLAGS as above because Distutils always generates the link directory options as pointing to the Host Python's install location.</p>
<p>We also need to set CC and LDSHARED because the compiler guessed out of the target Python Makefile is wrong for ELDK. If you are compiling C++ code you would also need to set the CXX environment variable.</p>
<p>Once you have the egg built, you can copy it over to a package directory (read an auto-indexed directory on a web server) and install it from your target using:</p>


<div class="pygments_murphy"><pre><span class="nv">$ </span>easy_install -f http://mylocalpackageplace/nest package_name
</pre></div>



<p>Concrete example time, what do you need in order to build the deps for and install <a class="reference external" href="http://turbogears.com">TurboGears 2</a>. You need the following packages:
zope.interface, Genshi, and simplejson. ELDK's installation of Python 2.5 does not seem to come with sqlite so you will either need to do a new cross compile of python or get a separate install of the sqlite library. Once you have your binary eggs built using the above command copy them to your local http server, I'll use 192.168.1.99. You need to follow the <a class="reference external" href="http://www.turbogears.org/2.0/docs/main/DownloadInstall.html#manual-installation">Manual Installation method for TurboGears</a> but when you get to <a class="reference external" href="http://www.turbogears.org/2.0/docs/main/DownloadInstall.html#install-turbogears-2">Install TurboGears 2</a> add &quot;<tt class="docutils literal"><span class="pre">-f</span> <span class="pre">http://192.168.1.99/nest/</span></tt>&quot; to the command line so that you get:</p>


<div class="pygments_murphy"><pre><span class="o">(</span>tg2env<span class="o">)</span><span class="nv">$ </span>easy_install -i http://www.turbogears.org/2.0/downloads/current/index -f http://192.168.1.99/nest/ tg.devtools
</pre></div>



<p>This is sufficient for most normal extension building situations. Unfortunately there are some extensions that use autotools and python-config instead of distutils (<a class="reference external" href="http://dbus.freedesktop.org/doc/dbus-python/">dbus-python</a> and <a class="reference external" href="http://omniorb.sourceforge.net/">omniORBpy</a> come to mind). Autotools should let you override the critical settings but I would like to see the situation improve.</p>
<p>Let me know if you have ideas on how to make Python development in an embedded environment better.</p>
<p><strong>Update:</strong> <a class="reference external" href="http://dirtsimple.org/programming/index.html">PJE</a>, the author of setuptools, has given notice of the impending release of setuptools 6c10 which fixes many bugs, including the Python 2.6.3 compile bug. See his comment below.</p>
</div>
]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://whatschrisdoing.com/blog/</uri>
    </author>
    <title type="html"><![CDATA[New Camera]]></title>
    <link rel="alternate" type="text/html" href="http://whatschrisdoing.com/blog/2009/07/01/new-camera/" />
    <id>http://whatschrisdoing.com/blog/2009/07/01/new-camera/</id>
    <updated>2009-07-01T15:47:51Z</updated>
    <published>2009-07-01T15:47:51Z</published>
    <category scheme="http://whatschrisdoing.com/blog/" term="Photography" />
    <category scheme="http://whatschrisdoing.com/blog/" term="Amara" />
    <category scheme="http://whatschrisdoing.com/blog/" term="General" />
    <summary type="html"><![CDATA[New Camera]]></summary>
    <content type="html" xml:base="http://whatschrisdoing.com/blog/2009/07/01/new-camera/"><![CDATA[<div class="document">
<div class="span6" style="float: left; margin-left: 0; margin-right: 10px;">
<ul class="thumbnails">
  <li class="span12">
    <a href="http://gallery.kateandchris.net/Category/People/Park-Snapshots/24292755_Dbv47T#!i=1978361276&k=DqCwtHs&lb=1&s=A" class="thumbnail">
      <img src="http://gallery.kateandchris.net/Category/People/Park-Snapshots/i-DqCwtHs/0/S/IMG0054-S.jpg" alt="">
    </a>
  </li>
</ul>
</div><p>My 30th birthday came and went on the 21st of June. I got a couple of toys including a new <a class="reference external" href="http://www.dpreview.com/news/0809/08091702canon_g10.asp">Canon G10 Camera</a>. I have been carrying it with me everywhere and have a few pictures up already. Most are from trips to the <a class="reference external" href="http://gallery.kateandchris.net/Category/People/Park-Snapshots/24292755_Dbv47T#!i=1978361276&amp;k=DqCwtHs">park</a>. But there are also a couple from <a class="reference external" href="http://gallery.kateandchris.net/Category/People/Amara-Year-3/24295590_pbrLmw#!i=1978608960&amp;k=Kb3LkSn">Amara's end of school year pageant</a> (look for the pictures in the church). Unfortunately for the pageant shots there were a lot of pushy parents trying to get pictures, so there are no shots of Amara singing.</p>
<div class="span5" style="float: right; margin-right: 0; margin-left: 10px;">
<ul class="thumbnails">
  <li class="span12">
    <a href="http://gallery.kateandchris.net/Category/People/Park-Snapshots/24292755_Dbv47T#!i=1978377961&k=PDKRJZT&lb=1&s=A" class="thumbnail">
      <img src="http://gallery.kateandchris.net/Category/People/Park-Snapshots/i-PDKRJZT/0/M/IMG0075-S.jpg" alt="">
    </a>
  </li>
</ul>
</div><p>The camera is taking some getting used to. The controls are very different from my 300D (Digital Rebel) but I think I am starting to get the hang of them. My main problem is that I am not as fast with the G10 as I am with the SLR. The zoom reacts much slower that I can with the manual zoom on the SLR so composition takes longer with that. I also am still getting the hang of changing the auto focus location.</p>
<p>The G10 does, however, have a snappy start up and I have yet to see it have a problem keeping up with the speed I want to take pictures at, a problem that has been plaguing me with the 300D. One of the reasons I wanted the G10 was that I can capture in RAW. My big disappointment so far has been that <a class="reference external" href="http://www.bibblelabs.com/">Bibble</a>, the software I use for my photo work does not yet have G10 support as they are between major releases. For the time being I am making due with the software that comes with the Camera, but it certainly does not have an optimized work flow. I don't want to have to shell out for something like <a class="reference external" href="http://www.adobe.com/products/photoshoplightroom/">Adobe Lightroom</a> but if Bibble does not get their act together soon, that might be the way I am headed.</p>
</div>
]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://whatschrisdoing.com/blog/</uri>
    </author>
    <title type="html"><![CDATA[Pictures, Pictures, Pictures]]></title>
    <link rel="alternate" type="text/html" href="http://whatschrisdoing.com/blog/2009/06/13/pictures-pictures-pictures/" />
    <id>http://whatschrisdoing.com/blog/2009/06/13/pictures-pictures-pictures/</id>
    <updated>2009-06-13T16:38:07Z</updated>
    <published>2009-06-13T16:38:07Z</published>
    <category scheme="http://whatschrisdoing.com/blog/" term="General" />
    <summary type="html"><![CDATA[Pictures, Pictures, Pictures]]></summary>
    <content type="html" xml:base="http://whatschrisdoing.com/blog/2009/06/13/pictures-pictures-pictures/"><![CDATA[<div class="document">
<div class="span6" style="float: right; margin-right: 0; margin-left: 10px;">
<ul class="thumbnails">
  <li class="span12">
    <a href="http://gallery.kateandchris.net/Category/Trips/Florida-April-2009/24297371_v4swnJ#!i=1978774486&k=bJBvVGg&lb=1&s=A" class="thumbnail">
      <img src="http://gallery.kateandchris.net/Category/Trips/Florida-April-2009/i-bJBvVGg/0/S/CRW2472-S.jpg" alt="">
    </a>
  </li>
</ul>
</div><p>I just posted lots of pictures to my <a class="reference external" href="http://gallery.kateandchris.net">Picture Gallery</a>. There are some from our <a class="reference external" href="http://gallery.kateandchris.net/Category/Trips/Florida-April-2009/">trip to Florida</a> and some from <a class="reference external" href="http://gallery.kateandchris.net/Category/Events/Welcome-Zane/">Zane's welcome party</a> and some <a class="reference external" href="http://gallery.kateandchris.net/Category/People/Amara-Year-3/">random pictures of Amara</a>.  I'll also post a few choice picks to my <a class="reference external" href="http://www.flickr.com/photos/chris_lambacher/">Flickr Stream</a>.</p>
</div>
]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://whatschrisdoing.com/blog/</uri>
    </author>
    <title type="html"><![CDATA[Protecting Plone Registration Forms with ReCAPTCHA]]></title>
    <link rel="alternate" type="text/html" href="http://whatschrisdoing.com/blog/2009/02/24/protecting-plone-registration-forms-with-recaptcha/" />
    <id>http://whatschrisdoing.com/blog/2009/02/24/protecting-plone-registration-forms-with-recaptcha/</id>
    <updated>2009-02-24T10:56:36Z</updated>
    <published>2009-02-24T10:56:36Z</published>
    <category scheme="http://whatschrisdoing.com/blog/" term="Computers" />
    <category scheme="http://whatschrisdoing.com/blog/" term="Programming" />
    <summary type="html"><![CDATA[Protecting Plone Registration Forms with ReCAPTCHA]]></summary>
    <content type="html" xml:base="http://whatschrisdoing.com/blog/2009/02/24/protecting-plone-registration-forms-with-recaptcha/"><![CDATA[<div class="document">
<p>We recently launched the <a class="reference external" href="http://community.cioc.ca/">CIOC Community Site</a> running on Plone. While we have not actually had any SPAM on the site yet, we continually get automated SPAM registrations that we then need to go and clear out. Last night Kate got fed up, so I decided to see if I could put a CAPTCHA on the form.</p>
<p>Looks like there is a <a class="reference external" href="http://plone.org/products/plone/roadmap/222/">proposal to include CAPTCHA support</a>. The <em>de facto standard</em> CAPTCHA tool for Plone seems to be <a class="reference external" href="http://plone.org/products/collective.captcha">collective.captcha</a>, but I wanted to be able to use the <a class="reference external" href="http://recaptcha.net/">ReCAPTCHA</a> service.</p>
<p>Luckily there is <a class="reference external" href="http://plone.org/products/collective.recaptcha/">collective.recaptcha</a> which is in beta and, while not listing any releases on the Plone site, is <a class="reference external" href="http://pypi.python.org/pypi/collective.recaptcha/">available from the Cheese Shop</a>. But, alas, there is no documentation. It is supposed to be a drop in replacement for collective.captcha so with a little sleuthing and I got it to work.  Here's how.</p>
<div class="section" id="installation">
<h1>Installation</h1>
<p>I am using the unified Unix installer so everything is done via buildout. Following the instructions on the <a class="reference external" href="http://plone.org/products/collective.captcha">collective.captcha</a> page we need to add <tt class="docutils literal">collective.recaptcha</tt> to your eggs list and <tt class="docutils literal">collective.recaptcha</tt> to your zcml list. Then run <tt class="docutils literal">./bin/buildout</tt> and restart your Plone instance.</p>
</div>
<div class="section" id="configuration">
<h1>Configuration</h1>
<p>We need to enter our private and public ReCAPTCHA keys in the collective.recaptcha setup form which is located at <a class="reference external" href="http://urltoyourplonesite.com/recaptcha-settings">http://urltoyourplonesite.com/recaptcha-settings</a></p>
</div>
<div class="section" id="registration-form-modifications">
<h1>Registration Form Modifications</h1>
<p>Using <a class="reference external" href="http://www.codesyntax.com/cs-workshop/blog/using-collective.captcha-in-custom-forms">this</a> site as a helpful reference I was able to figure out the additions I needed to make to the registration form and validator.</p>
<p>You need to go in through your Plone site setup into the <em>Zope Management Interface</em>. Navigate to portal_skins/plone_login. Click join_form and then the customize button. You should now be able to customize the form contents. Down near the bottom of the form there is a line:</p>


<div class="pygments_murphy"><pre><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;formControls&quot;</span><span class="nt">&gt;&lt;/div&gt;</span>
</pre></div>



<p>Above that line you need to add:</p>


<div class="pygments_murphy"><pre><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;field&quot;</span>
     <span class="na">tal:define=</span><span class="s">&quot;error errors/captcha|nothing;&quot;</span>
     <span class="na">tal:attributes=</span><span class="s">&quot;class python:test(error, &#39;field error&#39;, &#39;field&#39;)&quot;</span><span class="nt">&gt;</span>
  <span class="nt">&lt;label</span> <span class="na">for=</span><span class="s">&quot;captcha&quot;</span> <span class="na">i18n:translate=</span><span class="s">&quot;label_captcha&quot;</span><span class="nt">&gt;</span>Captcha<span class="nt">&lt;/label&gt;</span>

  <span class="nt">&lt;span</span> <span class="na">class=</span><span class="s">&quot;fieldRequired&quot;</span> <span class="na">title=</span><span class="s">&quot;Required&quot;</span>
        <span class="na">i18n:attributes=</span><span class="s">&quot;title&quot;</span>
        <span class="na">i18n:domain=</span><span class="s">&quot;plone&quot;</span>
        <span class="na">i18n:translate=</span><span class="s">&quot;label_required&quot;</span><span class="nt">&gt;</span>(Required)<span class="nt">&lt;/span&gt;</span>

  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">&quot;formHelp&quot;</span> <span class="na">i18n:translate=</span><span class="s">&quot;help_captcha&quot;</span><span class="nt">&gt;</span>
    Provide the text in the image. Just to avoid spambots
  <span class="nt">&lt;/div&gt;</span>
  <span class="nt">&lt;p</span> <span class="na">tal:replace=</span><span class="s">&quot;structure here/@@captcha/image_tag&quot;</span> <span class="nt">/&gt;</span>

<span class="nt">&lt;/div&gt;</span>
</pre></div>



<p>Note that the difference from the code provided by Mikel Larreategi is that ReCAPTACH provides the input element itself, so you need to omit the <tt class="docutils literal">div</tt> that includes the <tt class="docutils literal">&lt;input <span class="pre">type=&quot;text&quot;&gt;</span></tt> tag.</p>
<p>Once you have that saved, you need to go back to portal_skins/plone_login and click join_form_validate and once again click customize. At the bottom of the validation code, just before <tt class="docutils literal">return state</tt> add:</p>


<div class="pygments_murphy"><pre><span class="n">captcha</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="n">REQUEST</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">&#39;recaptcha_response_field&#39;</span><span class="p">)</span>
<span class="n">view</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="n">restrictedTraverse</span><span class="p">(</span><span class="s">&#39;@@captcha&#39;</span><span class="p">)</span>

<span class="k">if</span> <span class="ow">not</span> <span class="n">view</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span><span class="n">captcha</span><span class="p">):</span>
    <span class="n">state</span><span class="o">.</span><span class="n">setError</span><span class="p">(</span><span class="s">&#39;captcha&#39;</span><span class="p">,</span> <span class="n">_</span><span class="p">(</span><span class="s">u&#39;Are you a bot? Try again...&#39;</span><span class="p">))</span>
    <span class="n">state</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">status</span><span class="o">=</span><span class="s">&#39;failure&#39;</span><span class="p">)</span>
</pre></div>



<p>Note that the difference in the validation code from Mikel Larreategi's is that the ReCAPTCHA inserted input tag is called <tt class="docutils literal">recaptcha_response_field</tt> and not <tt class="docutils literal">captcha</tt>.</p>
<p>Hopefully that is helpful to someone other than me :)</p>
</div>
</div>
]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://whatschrisdoing.com/blog/</uri>
    </author>
    <title type="html"><![CDATA[Winterlicious X2 / AGO / Dirty Dancing]]></title>
    <link rel="alternate" type="text/html" href="http://whatschrisdoing.com/blog/2009/02/06/winterlicious-x2-ago-dirty-dancing/" />
    <id>http://whatschrisdoing.com/blog/2009/02/06/winterlicious-x2-ago-dirty-dancing/</id>
    <updated>2009-02-06T09:15:34Z</updated>
    <published>2009-02-06T09:15:34Z</published>
    <category scheme="http://whatschrisdoing.com/blog/" term="General" />
    <summary type="html"><![CDATA[Winterlicious X2 / AGO / Dirty Dancing]]></summary>
    <content type="html" xml:base="http://whatschrisdoing.com/blog/2009/02/06/winterlicious-x2-ago-dirty-dancing/"><![CDATA[<div class="document">
<p>Yesterday Kate and I had a very indulgent day. The <a class="reference external" href="http://www.toronto.com/winterlicious">Winterlicious</a> promotion is happening in Toronto right now and we decided to take full advantage of it. We booked a lunch and dinner reservation and then built a day in Toronto around it.</p>
<p>First we went to <a class="reference external" href="http://www.toronto.com/winterlicious/listing/125305">Barootes</a> for lunch. I had the Chicken, Leek and Barley soup while Kate had the Baby Organic Greens with Apple Cider Vinaigrette. The we both had Penne with Spicy Italian sausage in Basil Tomato Sauce and finished it off with their &quot;Special of the Week&quot; which was Chocolate Layer Cake. Yummy.</p>
<p>Once we left there we walked to the <a class="reference external" href="http://www.ago.net/">AGO</a> to check out the new building and have a look through the new collections. The walk was a <em>chilly</em> at -8C but we got there quick enough that we did completely loose the feeling in our extremities (about 10-15 minutes).</p>
<p>The <a class="reference external" href="http://www.ago.net/new-building">new AGO building</a> is a welcome change. It makes the building much more interesting and the extra exhibit space made for the opportunity to see many works that were locked away in the vaults before. Add the new works, and even if you were very familiar with what used to be on display, I am sure you will find something new to see.  The <a class="reference external" href="http://www.ago.net/transformation-ago-new-building">new centrepiece staircase</a> goes all the way up to the 5th floor and is outside the main structure of the building between the 4th and 5th floors similar to <a class="reference external" href="http://www.ago.net/new-building">the staircase on the other side of the building</a>. Disappointingly, they are having a major problem with condensation on the glass between the 4th and 5th floors of the staircase. They had to close that section of the staircase and the water is damaging the dry wall in places. After all the money and effort that went into the <a class="reference external" href="http://www.ago.net/transformation/">transformation</a> I hope they will be able to find a quick solution to the problem and it is just a matter of working out the kinks.</p>
<p>After about 4 hours at the AGO, it was time for the cold walk back to King St for our dinner at <a class="reference external" href="http://www.toronto.com/winterlicious/listing/213111">Marcel's Bistro</a>. Both Kate and I had the Salad to start, followed by Pork tenderloin in a tomato sauce with mashed potatoes &amp; seasonal vegetables. We shared a 1/2L of the Italian Terrazze Della Luna Pinot Grigio 2007. For desert Kate had Vanilla ice cream with hot chocolate sauce in puff pastry while I had the chocolate mouse cake. Again yummy, but I think Barootes was better.</p>
<p>To complete the day, we had tickets to <a class="reference external" href="http://www.dirtydancingtoronto.ca/">Dirty Dancing</a>. We had excellent seats, 3rd row, first balcony center which we got for the <a class="reference external" href="http://www.redflagdeals.com/deals/main.php/alldeals/comments/mirvish_productions_dirty_dancing_tickets_30_sound_of_music_family_pack_4_s">ridiculously low price of $30 each</a>. Thank you <a class="reference external" href="http://www.redflagdeals.com/">Red Flag Deals</a>. The play was good, but not your traditional the story line is sung kind of musical. It was more like a play with a lot of music and dancing in it. If you liked the movie, you'll probably like the play.</p>
<p>In all it was a very long, fun, expensive but high value day.</p>
</div>
]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://whatschrisdoing.com/blog/</uri>
    </author>
    <title type="html"><![CDATA[More ISAPI-WSGI and TurboGears]]></title>
    <link rel="alternate" type="text/html" href="http://whatschrisdoing.com/blog/2008/07/27/more-isapi-wsgi-and-turbogears/" />
    <id>http://whatschrisdoing.com/blog/2008/07/27/more-isapi-wsgi-and-turbogears/</id>
    <updated>2008-07-27T21:26:22Z</updated>
    <published>2008-07-27T21:26:22Z</published>
    <category scheme="http://whatschrisdoing.com/blog/" term="Programming" />
    <summary type="html"><![CDATA[More ISAPI-WSGI and TurboGears]]></summary>
    <content type="html" xml:base="http://whatschrisdoing.com/blog/2008/07/27/more-isapi-wsgi-and-turbogears/"><![CDATA[<div class="document">
<p>Apparently my <a class="reference external" href="http://whatschrisdoing.com/blog/2008/07/10/turbogears-isapi-wsgi-iis/">last post</a> was not <a class="reference external" href="http://compoundthinking.com/blog/index.php/2008/07/25/host-tg-on-iis/#comment-211784">sufficiently detailed</a> for some people.  Well, okay, so far only <a class="reference external" href="http://www.jaraco.com/">one person</a>, but I am sure I will eventually get a deluge of comments asking for clarification, so I decided to beat them to it :)</p>
<p>The best place to start is at the beginning.  IIS exposes a programming interface through DLLs that can be loaded into IIS called ISAPI.  There are two flavours of ISAPI, <a class="reference external" href="http://msdn.microsoft.com/en-us/library/ms525282.aspx">extensions</a> and <a class="reference external" href="http://msdn.microsoft.com/en-us/library/ms525103.aspx">filters</a>.  Filters operate against every request, while extensions target particular file types.  Often filters are used to implement things like <a class="reference external" href="http://www.codeplex.com/IIRF">URL rewriters</a> and gzip encoders, while extensions are used to add new file type handlers like php and asp.  Extensions can also handle .* files, which is special IIS lingo for &quot;send all requests to this extension&quot;.</p>
<p>The first problem we have is that we need to create a DLL that is loadable by IIS and exposes the expected interface.  Luckily <a class="reference external" href="http://sourceforge.net/projects/pywin32/">Python for Windows Extensions</a> provides a method for doing just that.  As part of the distribution, you get PyISAPI_loader.dll which can be found in the isapi module under site packages.  This DLL can be copied out into your work folder and renamed with a leading underscore, something like <tt class="docutils literal">_tgload.dll</tt>.  When added to your IIS web site and loaded, it will embed python into IIS and load a python file that is named like the DLL but without the underscore (<tt class="docutils literal">tgload.py</tt>).</p>
<p>You can program for either ISAPI filters or extensions with this DLL as the interface that IIS expects does not conflict and is dictated by how you load the DLL.  In our case we are creating an extension, so we add the DLL via the application settings section of the tab that might be named one of &quot;virtual directory&quot;, &quot;home directory&quot; or just plain &quot;directory&quot;.  If you haven't already done so you will need to click the &quot;Create&quot; button.  Click the &quot;Configuration...&quot; button to open the &quot;Application Configuration&quot; dialog.  Under the mappings tab, remove all of the existing application mappings and add a new one.  The executable should point to the dll from above, which does not need to and should not exist in the directory that would normally be served by IIS.  Set the extension to &quot;.*&quot; in order to catch all URLs, select &quot;All Verbs&quot; and uncheck both &quot;Script Engine&quot; and &quot;Check that file exists&quot;.</p>
<p>Programming an ISAPI extension in Python is essentially the same as in C because the isapi module that ships with Python for Windows Extensions does an excellent job of emulating the native interface.  <a class="reference external" href="http://msdn.microsoft.com/en-us/library/ms524338.aspx">Microsoft's documentation applies</a> equally well to Python as it does to C.  There are a couple of minor differences which I will document here as well as a couple of tips that will hopefully keep you from pulling your hair out when something goes wrong.  First, add the following lines to the top of your file:</p>


<div class="pygments_murphy"><pre><span class="kn">import</span> <span class="nn">sys</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">sys</span><span class="p">,</span> <span class="s">&quot;isapidllhandle&quot;</span><span class="p">):</span>
    <span class="kn">import</span> <span class="nn">win32traceutil</span>
</pre></div>



<p>This will detect when the file is loaded as an ISAPI extension or filter DLL and redirect stdout and stderr to the win32traceutil output collector.  You can run the trace utility by executing <tt class="docutils literal">python <span class="pre">-m</span> win32traceutil</tt> in order to see any output from your DLL, including uncaught exception backtraces.</p>
<p>You also need to export the <tt class="docutils literal">__ExtensionFactory__()</tt> function, which returns an object that exposes the <tt class="docutils literal">GetExtensionVersion</tt>, <tt class="docutils literal">HttpExtensionProc</tt> and <tt class="docutils literal">TerminateExtension</tt> methods that operate as described in the Microsoft documentation with the exception that the first variable passed will be <tt class="docutils literal">self</tt>.</p>
<p>Luckily you don't need to worry about the details of how all this works, because <a class="reference external" href="http://code.google.com/p/isapi-wsgi/">ISAPI-WSGI</a> provides this object for you.  It translates the ISAPI interface into the Python <a class="reference external" href="http://www.wsgi.org/">WSGI</a> interface.  If you haven't heard of it before, WSGI is <strong>THE</strong> standard for connecting Python applications to web servers in all their forms.  At this point all of the Python Frameworks talk WSGI so it is a pretty good bet for being able to connect to a Python Web app.</p>
<p>ISAPI-WSGI provides 2 flavours of ISAPI interface objects, <tt class="docutils literal">ISAPISimpleHandler</tt> and <tt class="docutils literal">ISAPIThreadPoolHandler</tt>.  The <tt class="docutils literal">ISAPISimpleHandler</tt> can only handle one request at a time, while the <tt class="docutils literal">ISAPIThreadPoolHandler</tt> does not block IIS and offloads the handling of the URL onto a pool of threads that call back into IIS when there is data to transmit back to the client.  The exposed interface is identical, so you can go ahead and use whatever your are comfortable with.</p>
<p>Okay so we are going to be returning an instance of <tt class="docutils literal">ISAPISimpleHandler</tt> or <tt class="docutils literal">ISAPIThreadPoolHandler</tt> from our module's <tt class="docutils literal">__ExtensionFactory__()</tt> function.  All we need to do is instantiate our choice of object and pass it our WSGI App interface.  For TurboGears, all of our HTTP requests are handled by <a class="reference external" href="http://cherrypy.org">CherryPy</a> so we need to dig into how CherryPy exposes a WSGI App.  That is what my <a class="reference external" href="http://whatschrisdoing.com/blog/2008/07/10/turbogears-isapi-wsgi-iis/">previous article</a> is supposed to explain.</p>
<p>All of this should work without a hitch on 32bit Windows, but 64bit opens up a whole big set of problems.  You cannot load 32bit DLLs into 64bit applications.  There is no <em>official</em> build of the Python for Windows Extensions.  I was able to find an <a class="reference external" href="http://mail.python.org/pipermail/python-list/2007-January/423258.html">old build for Python 2.4</a> and a <a class="reference external" href="http://sourceforge.net/project/platformdownload.php?group_id=78018">current (official) build for Python 2.6</a>, but I found no version for Python 2.5.</p>
<p>Now this does not mean you are dead in the water, IIS 6 (Windows Server 2003 and Windows XP) will let you choose to run IIS in 32bit mode, but <em>everything</em> must run in 32 bit mode.  If you want to do this, <a class="reference external" href="http://www.google.ca/search?q=asp.net+1+windows+x64&amp;ie=utf-8&amp;oe=utf-8&amp;aq=t&amp;rls=org.mozilla:en-GB:official&amp;client=firefox-a">search for ASP.NET 1.x and Windows x64</a>.  If you are sharing the server with other apps that you want to be running in 64bit, like ASP or ASP.NET 2+, you will need to find an alternative deployment method (I am going with TurboGears and IIS behind an Apache reverse proxy).  If you are on IIS 7 (Windows Server 2008 and Windows Vista) you can configure individual application pools to run in either 64bit or 32bit mode.  I don't have access to an IIS 7 server to try it out.  Anyone who can should report back in the comments.</p>
<p>Hopefully that fills the gaps that I left in the last article.  I'll leave it to someone else to distill this into newbie friendly documentation that can go on the TurboGears or ISAPI-WSGI Web sites.</p>
</div>
]]></content>
  </entry>
  <entry>
    <author>
      <name></name>
      <uri>http://whatschrisdoing.com/blog/</uri>
    </author>
    <title type="html"><![CDATA[TurboGears + ISAPI-WSGI + IIS]]></title>
    <link rel="alternate" type="text/html" href="http://whatschrisdoing.com/blog/2008/07/10/turbogears-isapi-wsgi-iis/" />
    <id>http://whatschrisdoing.com/blog/2008/07/10/turbogears-isapi-wsgi-iis/</id>
    <updated>2008-07-10T12:18:08Z</updated>
    <published>2008-07-10T12:18:08Z</published>
    <category scheme="http://whatschrisdoing.com/blog/" term="Programming" />
    <summary type="html"><![CDATA[TurboGears + ISAPI-WSGI + IIS]]></summary>
    <content type="html" xml:base="http://whatschrisdoing.com/blog/2008/07/10/turbogears-isapi-wsgi-iis/"><![CDATA[<div class="document">
<p>On June 19, 2008, Louis <a class="reference external" href="http://groups.google.com/group/isapi_wsgi-dev/browse_thread/thread/310c8e3de00d22e5">wrote</a> to the <a class="reference external" href="http://groups.google.com/group/isapi_wsgi-dev">isapi_wsgi-dev</a> Google Group asking about how to get <a class="reference external" href="http://www.cherrypy.org/">CherryPy</a> to work with <a class="reference external" href="http://code.google.com/p/isapi-wsgi/">ISAPI-WSGI</a>.  Since ISAPI-WSGI was how I was going to connect my <a class="reference external" href="http://turbogears.com/">Turbo Gears</a> app up to IIS, I recording what I did here for posterity.</p>
<p>The first caveat to this is that you will not get this to work with IIS in 64 bit mode unless you can get a build of <a class="reference external" href="http://sourceforge.net/projects/pywin32/">PyWin32</a> for x64.  If you running a 64bit Windows architecture you will need to set IIS to 32bit mode and only run 32bit ISAPI dlls.  On IIS6 (Windows 2003/XP) this will mean you can only run 32bit DLLs.  If you are using IIS7 (Windows 2008), you will, apparently, be able to have 64bit and 32bit process pools.  This situation could get better in Python 2.6 since PyWin32 seems to have a x64 build for the 2.6 alphas.</p>
<p>Okay, on to the explanation.  The first thing to do in your DLL Python file, is to include these lines:</p>


<div class="pygments_murphy"><pre><span class="kn">import</span> <span class="nn">sys</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">sys</span><span class="p">,</span> <span class="s">&quot;isapidllhandle&quot;</span><span class="p">):</span>
    <span class="kn">import</span> <span class="nn">win32traceutil</span>
</pre></div>



<p>This checks that we are running as an ISAPI DLL and imports win32traceutil, which redirects stdin and stdout so that you can view them with the win32traceutil message collector (just run the module on its own: python -m win32traceutil).  If things go wrong, at least you will have a way of knowing what is going wrong.</p>
<p>My __ExtensionFactory__() looks like this:</p>


<div class="pygments_murphy"><pre><span class="k">def</span> <span class="nf">__ExtensionFactory__</span><span class="p">():</span>
    <span class="c"># Do some pre import setup</span>
    <span class="kn">import</span> <span class="nn">os</span>

    <span class="n">app_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">__file__</span><span class="p">),</span> <span class="s">&#39;..&#39;</span><span class="p">,</span> <span class="s">&#39;app&#39;</span><span class="p">)</span>
    <span class="n">app_dir</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">normpath</span><span class="p">(</span><span class="n">app_dir</span><span class="p">)</span>
    <span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">app_dir</span><span class="p">)</span>
    <span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">app_dir</span><span class="p">)</span>

    <span class="c"># import my app creator</span>
    <span class="kn">import</span> <span class="nn">wsgi_myapp</span>
    <span class="k">return</span> <span class="n">ISAPIThreadPoolHandler</span><span class="p">(</span><span class="n">wsgi_myapp</span><span class="o">.</span><span class="n">wsgiApp</span><span class="p">)</span>
</pre></div>



<p>In the do some pre-import setup, we add the application dir to the import path and change directories so that the current working dir is where the TurboGears app is (start-yourproject.py).</p>
<p>Then I have the module that sets up the TurboGears/CherryPy WSGI app.  I started with the TurboGears start-yourapp.py file and made modifications that were appropriate for making it work properly with WSGI:</p>


<div class="pygments_murphy"><pre><span class="c">#!c:\Python25\python.exe</span>
<span class="kn">from</span> <span class="nn">turbogears</span> <span class="kn">import</span> <span class="n">config</span><span class="p">,</span> <span class="n">update_config</span>
<span class="kn">import</span> <span class="nn">cherrypy</span>
<span class="n">cherrypy</span><span class="o">.</span><span class="n">lowercase_api</span> <span class="o">=</span> <span class="bp">True</span>

<span class="c"># first look on the command line for a desired config file,</span>
<span class="c"># if it&#39;s not on the command line, then</span>
<span class="c"># look for setup.py in this directory. If it&#39;s not there, this script is</span>
<span class="c"># probably installed</span>
<span class="n">update_config</span><span class="p">(</span><span class="n">configfile</span><span class="o">=</span><span class="s">&quot;prod.cfg&quot;</span><span class="p">,</span><span class="n">modulename</span><span class="o">=</span><span class="s">&quot;yourapp.config&quot;</span><span class="p">)</span>
<span class="n">config</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="n">package</span><span class="o">=</span><span class="s">&quot;yourapp&quot;</span><span class="p">))</span>

<span class="kn">from</span> <span class="nn">yourapp.controllers</span> <span class="kn">import</span> <span class="n">Root</span>

<span class="n">cherrypy</span><span class="o">.</span><span class="n">root</span> <span class="o">=</span> <span class="n">Root</span><span class="p">()</span>
<span class="n">cherrypy</span><span class="o">.</span><span class="n">server</span><span class="o">.</span><span class="n">start</span><span class="p">(</span><span class="n">initOnly</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">serverClass</span><span class="o">=</span><span class="bp">None</span><span class="p">)</span>

<span class="kn">from</span> <span class="nn">cherrypy._cpwsgi</span> <span class="kn">import</span> <span class="n">wsgiApp</span>
</pre></div>



<p>The CherryPy critical components (for CherryPy 2.2) are:</p>


<div class="pygments_murphy"><pre><span class="c"># Grab your Root object</span>
<span class="kn">from</span> <span class="nn">yourapp.controllers</span> <span class="kn">import</span> <span class="n">Root</span>

<span class="c"># set the root object and initialize the server</span>
<span class="n">cherrypy</span><span class="o">.</span><span class="n">root</span> <span class="o">=</span> <span class="n">Root</span><span class="p">()</span>
<span class="n">cherrypy</span><span class="o">.</span><span class="n">server</span><span class="o">.</span><span class="n">start</span><span class="p">(</span><span class="n">initOnly</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">serverClass</span><span class="o">=</span><span class="bp">None</span><span class="p">)</span>

<span class="c"># expose the wsgiApp to be imported by the isapidll.py file above.</span>
<span class="kn">from</span> <span class="nn">cherrypy._cpwsgi</span> <span class="kn">import</span> <span class="n">wsgiApp</span>
</pre></div>



<p>Louis is using CherryPy 3 which changes things slightly from what I have done.  CherryPy 3 is all WSGI all the time so we need to do less fiddling.  Here is what he had for __ExtensionFactory__():</p>


<div class="pygments_murphy"><pre><span class="k">def</span> <span class="nf">__ExtensionFactory__</span><span class="p">():</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="c">#cpwsgiapp = cherrypy.Application(HelloWorld(),&#39;F:\python-work&#39;)</span>
        <span class="n">app</span> <span class="o">=</span> <span class="n">cherrypy</span><span class="o">.</span><span class="n">tree</span><span class="o">.</span><span class="n">mount</span><span class="p">(</span><span class="n">HelloWorld</span><span class="p">())</span>
        <span class="n">cherrypy</span><span class="o">.</span><span class="n">engine</span><span class="o">.</span><span class="n">start</span><span class="p">(</span><span class="n">blocking</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
        <span class="c">#wsgi_apps = [(&#39;/blog&#39;, blog), (&#39;/forum&#39;, forum)]</span>

        <span class="c">#server = wsgiserver.CherryPyWSGIServer((&#39;localhost&#39;, 8080), HelloWorld(), server_name=&#39;localhost&#39;)</span>

        <span class="k">return</span> <span class="n">isapi_wsgi</span><span class="o">.</span><span class="n">ISAPISimpleHandler</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
    <span class="k">finally</span><span class="p">:</span>
        <span class="c"># This ensures that any left-over threads are stopped as well.</span>
        <span class="n">cherrypy</span><span class="o">.</span><span class="n">engine</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
</pre></div>



<p>I left in his extra comments because they show how he got to where he is.  This looks like the basic start a server code shown in the tutorial.  I think the key issues here are the cherrypy.engine calls.  The <a class="reference external" href="http://www.cherrypy.org/wiki/WSGI">CherryPy WSGI Wiki page</a> does not mention the engine at all.  I would guess that what he actually needs is:</p>


<div class="pygments_murphy"><pre><span class="k">def</span> <span class="nf">__ExtensionFactory__</span><span class="p">():</span>
    <span class="n">app</span> <span class="o">=</span> <span class="n">cherrypy</span><span class="o">.</span><span class="n">tree</span><span class="o">.</span><span class="n">mount</span><span class="p">(</span><span class="n">HelloWorld</span><span class="p">())</span>
    <span class="k">return</span> <span class="n">isapi_wsgi</span><span class="o">.</span><span class="n">ISAPISimpleHandler</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
</pre></div>



<p>That said, I have not used CherryPy 3, so I have no direct experience.</p>
<p><strong>Update</strong>: Don't use autoreload with ISAPI-WSGI.  It won't work and if you don't use the win32traceutil you won't know why.</p>
<p>Also, I have added more background detail on how to use ISAPI with Python and the ISAPI-WSGI package <a class="reference external" href="http://whatschrisdoing.com/blog/2008/07/27/more-isapi-wsgi-and-turbogears/">here</a>.</p>
</div>
]]></content>
  </entry>
</feed>
