<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>KenKinder.com &#187; CherryPy</title>
	<atom:link href="http://kenkinder.com/tag/cherrypy/feed/" rel="self" type="application/rss+xml" />
	<link>http://kenkinder.com</link>
	<description>Ken Kinder&#039;s personal website</description>
	<lastBuildDate>Mon, 14 Jun 2010 22:27:25 +0000</lastBuildDate>
	
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>CherryPy v. Pylons</title>
		<link>http://kenkinder.com/2009/10/18/cherrypy-v-pylons/</link>
		<comments>http://kenkinder.com/2009/10/18/cherrypy-v-pylons/#comments</comments>
		<pubDate>Sun, 18 Oct 2009 16:12:27 +0000</pubDate>
		<dc:creator>Ken Kinder</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[CherryPy]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[mako]]></category>
		<category><![CDATA[Pylons]]></category>

		<guid isPermaLink="false">http://kenkinder.com/?p=194</guid>
		<description><![CDATA[Over various pints of beer, emails, and late-night twitter tweets, I&#8217;ve alone and with others wondered about whether a smart, well-adjusted programmer would use Pylons or CherryPy for all his web programming needs (and whether such a programmer would take the time to convert from CherryPy to Pylons). Pylons is newish to me, but I&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p>Over various pints of beer, emails, and late-night twitter tweets, I&#8217;ve alone and with others wondered about whether a smart, well-adjusted programmer would use <a href="http://pylonshq.com/">Pylons</a> or <a href="http://www.cherrypy.org/">CherryPy</a> for all his web programming needs (and whether such a programmer would take the time to convert from CherryPy to Pylons). Pylons is newish to me, but I&#8217;ve been using CherryPy (on and off) for years now. What troubles me about CherryPy is that despite all those years of experience, there are still parts of CherryPy I struggle with (and not just <a href="http://www.cherrypy.org/browser/trunk/cherrypy/lib/sessions.py?rev=2528#L389">this horrible while-true-except-pass loop</a>). Here are my partially collected thoughts. I&#8217;ll start with what bugs me enough about CherryPy for me to seek alternatives.</p>
<p><span id="more-194"></span></p>
<p>If you visit the URI <tt>/foo/bar/spam</tt>, CherryPy looks for a <tt>foo.bar</tt> controller with a <tt>spam</tt> action (sort of). There are other mostly irrelevant complexities (mount points for quasi-apps and such), but that&#8217;s the gist. You can write your own &#8220;dispatcher&#8221; in CherryPy to map URLs to executable code, or use ones such as the <a href="http://www.cherrypy.org/wiki/PageHandlers">RoutesDispatcher</a>, which uses <a href="http://routes.groovie.org/">Groovie Routes</a> to map URLs to code. But using your own component is always kind of a sour-tasting afterthought in CherryPy and you&#8217;re sometimes reminded of that, unpleasantly (for example, routes for static content do not work in RoutesDispatcher).</p>
<p>In version 3, CherryPy&#8217;s previously simple configuration system got kind of confusing. I started writing a lot of code like this:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">cherrypy.<span style="color: black;">config</span>.<span style="color: black;">update</span><span style="color: black;">&#40;</span>myConfig<span style="color: black;">&#41;</span>
app = cherrypy.<span style="color: black;">tree</span>.<span style="color: black;">mount</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span>, moreConfig<span style="color: black;">&#41;</span>
cherrypy.<span style="color: black;">config</span>.<span style="color: black;">update</span><span style="color: black;">&#40;</span>someFile<span style="color: black;">&#41;</span>
cherrypy.<span style="color: black;">quickstart</span><span style="color: black;">&#40;</span>app<span style="color: black;">&#41;</span></pre></div></div>

<p>CherryPy lets you pass in configuration options a number of ways: <em>In Python</em>: dicts passed to <tt>config.update</tt>, dicts passed to <tt>tree.mount</tt>, or dicts on your controller object. <em>In <a href="http://docs.python.org/library/configparser.html">ConfigParser</a> syntax</em>: as filenames passed to <tt>config.update</tt> or <tt>tree.mount</tt>. The problem is that I&#8217;m always left with trial-and-error in figuring out what options I have; configuration directives don&#8217;t work everywhere, and you&#8217;re given relatively little guidance finding out where. If the documentation were better, that might help, but it&#8217;s confusing no matter what.</p>
<p>Which brings me to my most significant grievance with CherryPy: Its documentation is mediocre and because it takes such a novel approach to so many things, it needs good documentation. Most of CherryPy&#8217;s documentation is on a loosely organized wiki that resembles someone&#8217;s lecture notes more than it resembles documentation. This makes finding specific pieces of information difficult; for example, the RoutesDispatcher from above is buried deep down on a page called &#8220;PageHandlers&#8221; and is otherwise mostly unmentioned. Sometimes the wiki looks helpful, such as on <a href="http://cherrypy.org/wiki/FileUpload">this file upload page</a>, but in practice the examples given are apparently built for an old version of the framework (&#8220;<tt>from cherrypy.lib.filter import basefilter</tt>&#8221; results in an ImportError).</p>
<p>You can always ask CherryPy&#8217;s mailing list, but be forewarned: it&#8217;s not very inhabited now that TurboGears moved to Pylons.</p>
<p><strong>Where is CherryPy superior?</strong></p>
<p>After all these gripes, you might think I&#8217;m fully convinced that move to Pylons is good. A simple &#8220;Hello World&#8221; comparison reveals why that&#8217;s not the case. In CherryPy:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> cherrypy
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> HelloWorld<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> index<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;Hello World!&quot;</span>
    index.<span style="color: black;">exposed</span> = <span style="color: #008000;">True</span>
&nbsp;
cherrypy.<span style="color: black;">quickstart</span><span style="color: black;">&#40;</span>HelloWorld<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>In Pylons: &#8230; this is going to take some time. Pylons doesn&#8217;t let you create a Hello World app in one file. Or even one directory. You start by running this command (for convenience and comic effect, there are scroll bars):</p>
<pre lang="python" style="height: 200px; overflow: scroll;">
kkinder@kkinder-laptop ~> paster create MyHelloWorldProject -t pylons
Selected and implied templates:
  Pylons#pylons  Pylons application template

Variables:
  egg:      MyHelloWorldProject
  package:  myhelloworldproject
  project:  MyHelloWorldProject
Enter template_engine (mako/genshi/jinja2/etc: Template language) ['mako']:
Enter sqlalchemy (True/False: Include SQLAlchemy 0.5 configuration) [False]:
Creating template pylons
Creating directory ./MyHelloWorldProject
  Recursing into +package+
    Creating ./MyHelloWorldProject/myhelloworldproject/
    Copying templates/default_project/+package+/__init__.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/__init__.py
    Recursing into config
      Creating ./MyHelloWorldProject/myhelloworldproject/config/
      Copying templates/default_project/+package+/config/__init__.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/config/__init__.py
      Copying templates/default_project/+package+/config/deployment.ini_tmpl_tmpl to ./MyHelloWorldProject/myhelloworldproject/config/deployment.ini_tmpl
      Copying templates/default_project/+package+/config/environment.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/config/environment.py
      Copying templates/default_project/+package+/config/middleware.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/config/middleware.py
      Copying templates/default_project/+package+/config/routing.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/config/routing.py
    Recursing into controllers
      Creating ./MyHelloWorldProject/myhelloworldproject/controllers/
      Copying templates/default_project/+package+/controllers/__init__.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/controllers/__init__.py
      Copying templates/default_project/+package+/controllers/error.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/controllers/error.py
    Recursing into lib
      Creating ./MyHelloWorldProject/myhelloworldproject/lib/
      Copying templates/default_project/+package+/lib/__init__.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/lib/__init__.py
      Copying templates/default_project/+package+/lib/app_globals.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/lib/app_globals.py
      Copying templates/default_project/+package+/lib/base.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/lib/base.py
      Copying templates/default_project/+package+/lib/helpers.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/lib/helpers.py
    Recursing into model
      Creating ./MyHelloWorldProject/myhelloworldproject/model/
      Copying templates/default_project/+package+/model/__init__.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/model/__init__.py
    Recursing into public
      Creating ./MyHelloWorldProject/myhelloworldproject/public/
      Copying templates/default_project/+package+/public/bg.png to ./MyHelloWorldProject/myhelloworldproject/public/bg.png
      Copying templates/default_project/+package+/public/favicon.ico to ./MyHelloWorldProject/myhelloworldproject/public/favicon.ico
      Copying templates/default_project/+package+/public/index.html_tmpl to ./MyHelloWorldProject/myhelloworldproject/public/index.html
      Copying templates/default_project/+package+/public/pylons-logo.gif to ./MyHelloWorldProject/myhelloworldproject/public/pylons-logo.gif
    Recursing into templates
      Creating ./MyHelloWorldProject/myhelloworldproject/templates/
    Recursing into tests
      Creating ./MyHelloWorldProject/myhelloworldproject/tests/
      Copying templates/default_project/+package+/tests/__init__.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/tests/__init__.py
      Recursing into functional
        Creating ./MyHelloWorldProject/myhelloworldproject/tests/functional/
        Copying templates/default_project/+package+/tests/functional/__init__.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/tests/functional/__init__.py
      Copying templates/default_project/+package+/tests/test_models.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/tests/test_models.py
    Copying templates/default_project/+package+/websetup.py_tmpl to ./MyHelloWorldProject/myhelloworldproject/websetup.py
  Copying templates/default_project/MANIFEST.in_tmpl to ./MyHelloWorldProject/MANIFEST.in
  Copying templates/default_project/README.txt_tmpl to ./MyHelloWorldProject/README.txt
  Copying templates/default_project/development.ini_tmpl to ./MyHelloWorldProject/development.ini
  Recursing into docs
    Creating ./MyHelloWorldProject/docs/
    Copying templates/default_project/docs/index.txt_tmpl to ./MyHelloWorldProject/docs/index.txt
  Copying templates/default_project/ez_setup.py to ./MyHelloWorldProject/ez_setup.py
  Copying templates/default_project/setup.cfg_tmpl to ./MyHelloWorldProject/setup.cfg
  Copying templates/default_project/setup.py_tmpl to ./MyHelloWorldProject/setup.py
  Copying templates/default_project/test.ini_tmpl to ./MyHelloWorldProject/test.ini
Running /usr/bin/python setup.py egg_info
</pre>
<p>I of course went for the lighter option that doesn&#8217;t include <a href="http://www.sqlalchemy.org/">SQLAlchemy</a>. Okay, we&#8217;re almost there. Now I&#8217;m going to create a Hello controller:</p>
<pre>
kkinder@kkinder-laptop ~/MyHelloWorldProject> paster controller Hello
Creating /home/kkinder/MyHelloWorldProject/myhelloworldproject/controllers/Hello.py
Creating /home/kkinder/MyHelloWorldProject/myhelloworldproject/tests/functional/test_Hello.py
</pre>
<p>This is where Pylons READS MY MIND and does the work for me. Take a look at the new <tt>Hello.py</tt> controller it made for me:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">logging</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> pylons <span style="color: #ff7700;font-weight:bold;">import</span> request, response, session, tmpl_context <span style="color: #ff7700;font-weight:bold;">as</span> c
<span style="color: #ff7700;font-weight:bold;">from</span> pylons.<span style="color: black;">controllers</span>.<span style="color: black;">util</span> <span style="color: #ff7700;font-weight:bold;">import</span> abort, redirect_to
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> myhelloworldproject.<span style="color: black;">lib</span>.<span style="color: black;">base</span> <span style="color: #ff7700;font-weight:bold;">import</span> BaseController, render
&nbsp;
log = <span style="color: #dc143c;">logging</span>.<span style="color: black;">getLogger</span><span style="color: black;">&#40;</span>__name__<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> HelloController<span style="color: black;">&#40;</span>BaseController<span style="color: black;">&#41;</span>:
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> index<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># Return a rendered template</span>
        <span style="color: #808080; font-style: italic;">#return render('/Hello.mako')</span>
        <span style="color: #808080; font-style: italic;"># or, return a response</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">'Hello World'</span></pre></div></div>

<p>But I&#8217;m not done yet. Now I need to edit my routing.py file, check my development.ini for any settings, run &#8220;setup.py develop&#8221; and then use &#8220;paster serve&#8221; to finally test my app. By the time I&#8217;m done printing &#8220;Hello World&#8221;, I have 42 files in 11 directories:</p>
<pre style="height: 200px; overflow: scroll">
.
|-- MANIFEST.in
|-- MyHelloWorldProject.egg-info
|   |-- PKG-INFO
|   |-- SOURCES.txt
|   |-- dependency_links.txt
|   |-- entry_points.txt
|   |-- not-zip-safe
|   |-- paster_plugins.txt
|   |-- requires.txt
|   `-- top_level.txt
|-- README.txt
|-- development.ini
|-- docs
|   `-- index.txt
|-- ez_setup.py
|-- myhelloworldproject
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- config
|   |   |-- __init__.py
|   |   |-- deployment.ini_tmpl
|   |   |-- environment.py
|   |   |-- middleware.py
|   |   `-- routing.py
|   |-- controllers
|   |   |-- Hello.py
|   |   |-- __init__.py
|   |   `-- error.py
|   |-- lib
|   |   |-- __init__.py
|   |   |-- __init__.pyc
|   |   |-- app_globals.py
|   |   |-- base.py
|   |   |-- base.pyc
|   |   `-- helpers.py
|   |-- model
|   |   `-- __init__.py
|   |-- public
|   |   |-- bg.png
|   |   |-- favicon.ico
|   |   |-- index.html
|   |   `-- pylons-logo.gif
|   |-- templates
|   |-- tests
|   |   |-- __init__.py
|   |   |-- functional
|   |   |   |-- __init__.py
|   |   |   `-- test_Hello.py
|   |   `-- test_models.py
|   `-- websetup.py
|-- setup.cfg
|-- setup.py
`-- test.ini

11 directories, 42 files
</pre>
<p>The Django/Pylons/TurboGears frameworks all follow a teeth gnashing design pattern that came out of Java and was made ugly in Ruby: Code generation. This is just my opinion, but in a language as dynamic and meta-programmative as Python, code generation is obsolete <em>at best</em>. What happens when the basic layout for a project changes a bit in the next version of Pylons? Do I &#8220;diff&#8221; the paste template and compare it to the old version to see what changed? And half of the configuration is in Pylon&#8217;s WSGI-obsessed middleware.py file, which is itself both a product of code generation and subsequent edits by the developer:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;Pylons middleware initialization&quot;&quot;&quot;</span>
<span style="color: #ff7700;font-weight:bold;">from</span> beaker.<span style="color: black;">middleware</span> <span style="color: #ff7700;font-weight:bold;">import</span> CacheMiddleware, SessionMiddleware
<span style="color: #ff7700;font-weight:bold;">from</span> paste.<span style="color: black;">cascade</span> <span style="color: #ff7700;font-weight:bold;">import</span> Cascade
<span style="color: #ff7700;font-weight:bold;">from</span> paste.<span style="color: black;">registry</span> <span style="color: #ff7700;font-weight:bold;">import</span> RegistryManager
<span style="color: #ff7700;font-weight:bold;">from</span> paste.<span style="color: black;">urlparser</span> <span style="color: #ff7700;font-weight:bold;">import</span> StaticURLParser
<span style="color: #ff7700;font-weight:bold;">from</span> paste.<span style="color: black;">deploy</span>.<span style="color: black;">converters</span> <span style="color: #ff7700;font-weight:bold;">import</span> asbool
<span style="color: #ff7700;font-weight:bold;">from</span> pylons <span style="color: #ff7700;font-weight:bold;">import</span> config
<span style="color: #ff7700;font-weight:bold;">from</span> pylons.<span style="color: black;">middleware</span> <span style="color: #ff7700;font-weight:bold;">import</span> ErrorHandler, StatusCodeRedirect
<span style="color: #ff7700;font-weight:bold;">from</span> pylons.<span style="color: black;">wsgiapp</span> <span style="color: #ff7700;font-weight:bold;">import</span> PylonsApp
<span style="color: #ff7700;font-weight:bold;">from</span> routes.<span style="color: black;">middleware</span> <span style="color: #ff7700;font-weight:bold;">import</span> RoutesMiddleware
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> myhelloworldproject.<span style="color: black;">config</span>.<span style="color: black;">environment</span> <span style="color: #ff7700;font-weight:bold;">import</span> load_environment
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> make_app<span style="color: black;">&#40;</span>global_conf, full_stack=<span style="color: #008000;">True</span>, static_files=<span style="color: #008000;">True</span>, <span style="color: #66cc66;">**</span>app_conf<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;&quot;Create a Pylons WSGI application and return it
&nbsp;
    ``global_conf``
        The inherited configuration for this application. Normally from
        the [DEFAULT] section of the Paste ini file.
&nbsp;
    ``full_stack``
        Whether this application provides a full WSGI stack (by default,
        meaning it handles its own exceptions and errors). Disable
        full_stack when this application is &quot;managed&quot; by another WSGI
        middleware.
&nbsp;
    ``static_files``
        Whether this application serves its own static files; disable
        when another web server is responsible for serving them.
&nbsp;
    ``app_conf``
        The application's local configuration. Normally specified in
        the [app:&lt;name&gt;] section of the Paste ini file (where &lt;name&gt;
        defaults to main).
&nbsp;
    &quot;&quot;&quot;</span>
    <span style="color: #808080; font-style: italic;"># Configure the Pylons environment</span>
    load_environment<span style="color: black;">&#40;</span>global_conf, app_conf<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># The Pylons WSGI app</span>
    app = PylonsApp<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Routing/Session/Cache Middleware</span>
    app = RoutesMiddleware<span style="color: black;">&#40;</span>app, config<span style="color: black;">&#91;</span><span style="color: #483d8b;">'routes.map'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
    app = SessionMiddleware<span style="color: black;">&#40;</span>app, config<span style="color: black;">&#41;</span>
    app = CacheMiddleware<span style="color: black;">&#40;</span>app, config<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> asbool<span style="color: black;">&#40;</span>full_stack<span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># Handle Python exceptions</span>
        app = ErrorHandler<span style="color: black;">&#40;</span>app, global_conf, <span style="color: #66cc66;">**</span>config<span style="color: black;">&#91;</span><span style="color: #483d8b;">'pylons.errorware'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Display error documents for 401, 403, 404 status codes (and</span>
        <span style="color: #808080; font-style: italic;"># 500 when debug is disabled)</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> asbool<span style="color: black;">&#40;</span>config<span style="color: black;">&#91;</span><span style="color: #483d8b;">'debug'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>:
            app = StatusCodeRedirect<span style="color: black;">&#40;</span>app<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            app = StatusCodeRedirect<span style="color: black;">&#40;</span>app, <span style="color: black;">&#91;</span><span style="color: #ff4500;">400</span>, <span style="color: #ff4500;">401</span>, <span style="color: #ff4500;">403</span>, <span style="color: #ff4500;">404</span>, <span style="color: #ff4500;">500</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Establish the Registry for this application</span>
    app = RegistryManager<span style="color: black;">&#40;</span>app<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span> asbool<span style="color: black;">&#40;</span>static_files<span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># Serve static files</span>
        static_app = StaticURLParser<span style="color: black;">&#40;</span>config<span style="color: black;">&#91;</span><span style="color: #483d8b;">'pylons.paths'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'static_files'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
        app = Cascade<span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>static_app, app<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> app</pre></div></div>

<p>Beyond its sanity in <em>not</em> generating piles of code, CherryPy has other advantages. Its testing framework is very easy to use, but and also <a href="http://www.cherrypy.org/wiki/Testing">documented with almost no examples</a>. Pylons, in contrast, tells you where to put the tests but doesn&#8217;t make it quite as easy to run them.</p>
<p>On a day to day basis, writing code in CherryPy is seldom a chore; it isn&#8217;t exciting or cutting edge, but it&#8217;s simple and usually CherryPy does a good job of staying out of your way. I&#8217;m never left wondering in CherryPy whether there is a specific &#8220;CherryPy way to do it,&#8221; while in Pylons, my framework even has an opinion on what Javascript library I choose (it likes script.aculo.us, although it doesn&#8217;t bang you over the head with it). CherryPy is usually simpler: take a look at <a href="http://static.repoze.org/whodocs/">repoze.who/what</a> or <a href="http://authkit.org/">AuthKit</a> in the Pylons world and compare a very simple <a href="http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions">CherryPy auth example</a>.</p>
<p>But there are places where Pylons is amazing&#8230;</p>
<p><strong>One more thing: What&#8217;s missing from CherryPy?</strong></p>
<p>Pylons error handling is the one killer feature it has that CherryPy just lacks. Skip to line 598 of the &#8220;Hello, World&#8221; pylons project and try throwing an error:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">    <span style="color: #ff7700;font-weight:bold;">def</span> index<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;">raise</span> <span style="color: #008000;">ValueError</span></pre></div></div>

<p>Then use the controller. In CherryPy, I would get a Python traceback wrapped in a &lt;pre&gt; tag. In Pylons, I get an ajax debugger with expression evaluation and variable inspection:</p>
<p><a href="http://kenkinder.com/wp-content/uploads/2009/08/screenshot1.png"><img src="http://kenkinder.com/wp-content/uploads/2009/08/screenshot1.png" alt="Pylons Screenshot" title="Pylons Screenshot" width="850" height="288" class="alignnone size-full wp-image-225" /></a><br/></p>
<p>I can inspect variables and evaluate expressions at each point in the traceback:</p>
<p><a href="http://kenkinder.com/wp-content/uploads/2009/08/screenshot2.png"><img src="http://kenkinder.com/wp-content/uploads/2009/08/screenshot2.png" alt="Pylons Screenshot" title="Pylons Screenshot" width="877" height="830" class="alignnone size-full wp-image-226" /></a></p>
<p>Along with view environment info, complete source code of running file and template, and more.</p>
<p><strong>Wrapping it up</strong></p>
<p>I normally would have a strong aversion to &#8220;glue&#8221; frameworks that try (usually badly) to integrate unrelated toolsets. Having said that, when I sit down and build my own framework in CherryPy, I want to use SQLAlchemy, Groovie Routes, and <a href="http://www.makotemplates.org/">Mako templates</a>. (Pylons&#8217; &#8220;webhelpers&#8221; are nice too.)</p>
<p>Pylons offers all those those tools in a bundle. Also, its mailing list is far more active. While CherryPy manages a post or two a day, Pylons has a high quality post every hour or more. I&#8217;m not saying I&#8217;m giving up on CherryPy, but if I started a project today, I would seriously consider Pylons as a more friendly alternative, even if it relies on code generation.</p>
]]></content:encoded>
			<wfw:commentRss>http://kenkinder.com/2009/10/18/cherrypy-v-pylons/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>MySQL (MySQLdb) sessions on CherryPy</title>
		<link>http://kenkinder.com/2008/12/29/mysql-mysqldb-sessions-on-cherrypy/</link>
		<comments>http://kenkinder.com/2008/12/29/mysql-mysqldb-sessions-on-cherrypy/#comments</comments>
		<pubDate>Mon, 29 Dec 2008 23:44:40 +0000</pubDate>
		<dc:creator>Ken Kinder</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[CherryPy]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[MySQLdb]]></category>

		<guid isPermaLink="false">http://kenkinder.com/?p=163</guid>
		<description><![CDATA[No such module existed, so I wrote one. Using it is pretty simple:


&#34;&#34;&#34;
Example code using mysqlsession.py
&#34;&#34;&#34;
from mysqlsession import MySQLSession
import cherrypy
import logging
&#160;
logging.basicConfig&#40;level=logging.DEBUG&#41;
&#160;
sessionInfo = &#123;
    'tools.sessions.on': True,
    'tools.sessions.storage_type': &#34;Mysql&#34;,
    'tools.sessions.connect_arguments': &#123;'db': 'sessions'&#125;,
    'tools.sessions.table_name': 'session'
&#125;
&#160;
cherrypy.config.update&#40;sessionInfo&#41;
&#160;
class HelloWorld:
    def index&#40;self&#41;:
      [...]]]></description>
			<content:encoded><![CDATA[<p>No such module existed, so I wrote one. Using it is pretty simple:</p>
<p><span id="more-163"></span></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #483d8b;">&quot;&quot;&quot;
Example code using mysqlsession.py
&quot;&quot;&quot;</span>
<span style="color: #ff7700;font-weight:bold;">from</span> mysqlsession <span style="color: #ff7700;font-weight:bold;">import</span> MySQLSession
<span style="color: #ff7700;font-weight:bold;">import</span> cherrypy
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">logging</span>
&nbsp;
<span style="color: #dc143c;">logging</span>.<span style="color: black;">basicConfig</span><span style="color: black;">&#40;</span>level=<span style="color: #dc143c;">logging</span>.<span style="color: black;">DEBUG</span><span style="color: black;">&#41;</span>
&nbsp;
sessionInfo = <span style="color: black;">&#123;</span>
    <span style="color: #483d8b;">'tools.sessions.on'</span>: <span style="color: #008000;">True</span>,
    <span style="color: #483d8b;">'tools.sessions.storage_type'</span>: <span style="color: #483d8b;">&quot;Mysql&quot;</span>,
    <span style="color: #483d8b;">'tools.sessions.connect_arguments'</span>: <span style="color: black;">&#123;</span><span style="color: #483d8b;">'db'</span>: <span style="color: #483d8b;">'sessions'</span><span style="color: black;">&#125;</span>,
    <span style="color: #483d8b;">'tools.sessions.table_name'</span>: <span style="color: #483d8b;">'session'</span>
<span style="color: black;">&#125;</span>
&nbsp;
cherrypy.<span style="color: black;">config</span>.<span style="color: black;">update</span><span style="color: black;">&#40;</span>sessionInfo<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> HelloWorld:
    <span style="color: #ff7700;font-weight:bold;">def</span> index<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        v = cherrypy.<span style="color: black;">session</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'v'</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
        cherrypy.<span style="color: black;">session</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'v'</span><span style="color: black;">&#93;</span> = v+<span style="color: #ff4500;">1</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;Hello world! %s&quot;</span> <span style="color: #66cc66;">%</span> v
&nbsp;
    index.<span style="color: black;">exposed</span> = <span style="color: #008000;">True</span>
&nbsp;
cherrypy.<span style="color: black;">quickstart</span><span style="color: black;">&#40;</span>HelloWorld<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Download the module: <a href="/wp-content/uploads/2008/12/mysqlsession.py.zip">mysqlsession.py</a></p>
<p>I would publish it formally, but I&#8217;m going to see if I can just have it added to the CherryPy project.</p>
<p>UPDATE: I took out the table locking and used InnoDB select-for-update locking.</p>
]]></content:encoded>
			<wfw:commentRss>http://kenkinder.com/2008/12/29/mysql-mysqldb-sessions-on-cherrypy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Worst lock acquisition code ever.</title>
		<link>http://kenkinder.com/2008/11/24/worst-lock-acquisition-code-ever/</link>
		<comments>http://kenkinder.com/2008/11/24/worst-lock-acquisition-code-ever/#comments</comments>
		<pubDate>Tue, 25 Nov 2008 05:27:01 +0000</pubDate>
		<dc:creator>Ken Kinder</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Bugs]]></category>
		<category><![CDATA[CherryPy]]></category>

		<guid isPermaLink="false">/?p=82</guid>
		<description><![CDATA[Courtesy of CherryPy:

while True:
    try:
        lockfd = os.open&#40;path, os.O_CREAT&#124;os.O_WRONLY&#124;os.O_EXCL&#41;
    except OSError:
        time.sleep&#40;0.1&#41;
    else:
        os.close&#40;lockfd&#41;
        break
self.locked = True

Really people, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.cherrypy.org/browser/tags/cherrypy-3.1.1/cherrypy/lib/sessions.py">Courtesy of CherryPy</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        lockfd = <span style="color: #dc143c;">os</span>.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span>path, <span style="color: #dc143c;">os</span>.<span style="color: black;">O_CREAT</span>|os.<span style="color: black;">O_WRONLY</span>|os.<span style="color: black;">O_EXCL</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">OSError</span>:
        <span style="color: #dc143c;">time</span>.<span style="color: black;">sleep</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0.1</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">else</span>:
        <span style="color: #dc143c;">os</span>.<span style="color: black;">close</span><span style="color: black;">&#40;</span>lockfd<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">break</span>
<span style="color: #008000;">self</span>.<span style="color: black;">locked</span> = <span style="color: #008000;">True</span></pre></div></div>

<p>Really people, really? We silently loop until an error goes away? <a href="http://groups.google.com/group/cherrypy-devel/browse_thread/thread/5c02051b151bc916?pli=1">Really</a>? </p>
]]></content:encoded>
			<wfw:commentRss>http://kenkinder.com/2008/11/24/worst-lock-acquisition-code-ever/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>
