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

<channel>
	<title>Planet CherryPy</title>
	<link>http://www.cherrypy.org/</link>
	<language>en</language>
	<description>Planet CherryPy - http://www.cherrypy.org/</description>

<item>
	<title>Kevin Dangoor: MichiPUG September Meeting: Titus reveals secrets of the PSF and MSU</title>
	<guid>http://www.blueskyonmars.com/2008/08/29/michipug-september-meeting-titus-reveals-secrets-of-the-psf-and-msu/</guid>
	<link>http://www.blueskyonmars.com/2008/08/29/michipug-september-meeting-titus-reveals-secrets-of-the-psf-and-msu/</link>
	<description>&lt;p&gt;The September meeting of the &lt;a href=&quot;http://groups.google.com/group/michipug/web/index-2&quot;&gt;Michigan Python Users Group (MichiPUG)&lt;/a&gt; is coming up on Thursday, September 4. This meeting marks the third birthday of the group!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://ivory.idyll.org/blog&quot;&gt;Titus Brown&lt;/a&gt; will be presenting to us on a &lt;a href=&quot;http://www.python.org/psf/&quot;&gt;Python Software Foundation&lt;/a&gt;-related project, as well as some of the things he has going on in his classes at Michigan State University. If you&amp;#8217;re taking one of Titus&amp;#8217; classes, this might be a good way to get a head start &lt;img src=&quot;http://www.blueskyonmars.com/wp-includes/images/smilies/icon_smile.gif&quot; alt=&quot;:)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;
&lt;p&gt;The meeting is at 7PM at the &lt;a href=&quot;http://srtsolutions.com/&quot;&gt;SRT Solutions&lt;/a&gt; office in downtown Ann Arbor (corner of Fifth and Washington).&lt;/p&gt;</description>
	<pubDate>Fri, 29 Aug 2008 12:41:10 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: The Tech of SitePen Support</title>
	<guid>http://www.blueskyonmars.com/2008/08/20/the-tech-of-sitepen-support/</guid>
	<link>http://www.blueskyonmars.com/2008/08/20/the-tech-of-sitepen-support/</link>
	<description>&lt;p&gt;I&amp;#8217;ve just posted an article with some details on how SitePen&amp;#8217;s Support system is built. We use Python on the server and Dojo-driven JavaScript on the browser to create a responsive system. The model we use is similar to what I described in my PyCon 2008 talk where the client is driving the interaction rather than the server.&lt;/p&gt;
&lt;blockquote cite=&quot;http://www.sitepen.com/blog/2008/08/19/the-tech-of-sitepen-support/#comment-87696&quot;&gt;
&lt;p&gt;SitePen’s Support service is built using a variety of interesting techniques and technologies. Read on to see how we built a system that treats the web browser as a real client tier and bridges the worlds of JavaScript, Python and PHP seamlessly to provide a great experience for our customers.&lt;/p&gt;
&lt;p&gt;[From &lt;a href=&quot;http://www.sitepen.com/blog/2008/08/19/the-tech-of-sitepen-support/#comment-87696&quot;&gt;&lt;cite&gt;SitePen Blog » The Tech of SitePen Support&lt;/cite&gt;&lt;/a&gt;]
&lt;/p&gt;&lt;/blockquote&gt;</description>
	<pubDate>Wed, 20 Aug 2008 11:07:03 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: MichiPUG this week: TurboGears 2</title>
	<guid>http://www.blueskyonmars.com/2008/08/04/michipug-this-week-turbogears-2/</guid>
	<link>http://www.blueskyonmars.com/2008/08/04/michipug-this-week-turbogears-2/</link>
	<description>&lt;p&gt;&lt;a href=&quot;http://turbogears.org/2.0/docs/&quot;&gt;TurboGears 2&lt;/a&gt; is currently out in alpha test releases and is rapidly approaching maturity (I know a few people using it in production already). This week at MichiPUG, Mark Ramm will be showing off the good stuff in TG2.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://groups.google.com/group/michipug/web/index-2&quot;&gt;Michigan Python Users Group&lt;/a&gt; meeting will be Thursday, August 7th at 7PM.&lt;/p&gt;
&lt;p&gt;See you there!&lt;/p&gt;</description>
	<pubDate>Mon, 04 Aug 2008 13:00:38 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Thanks to Mark for channelling me at PyOhio</title>
	<guid>http://www.blueskyonmars.com/2008/07/29/thanks-to-mark-for-channelling-me-at-pyohio/</guid>
	<link>http://www.blueskyonmars.com/2008/07/29/thanks-to-mark-for-channelling-me-at-pyohio/</link>
	<description>&lt;p&gt;I had lunch with &lt;a href=&quot;http://compoundthinking.com/blog/&quot;&gt;Mark Ramm-Christensen&lt;/a&gt; today, and he gave me the scoop on &lt;a href=&quot;http://www.pyohio.org/&quot;&gt;PyOhio&lt;/a&gt; which was last Saturday. It sounds like a good time was had by all. Mark guessed there were 80 people there, which is a good turnout for a regional event like PyOhio! Congrats to the organizers! It sounds like you did quite a job getting the word out and building the turnout.&lt;/p&gt;
&lt;p&gt;I couldn&amp;#8217;t be there because my daughter&amp;#8217;s 5th birthday party was on the same day. Thanks to Mark, my &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/&quot;&gt;Paver&lt;/a&gt; talk happened at PyOhio anyhow. He had the tough 2:30PM timeslot. If you&amp;#8217;ve ever given a talk or sat through a talk at 2:30, you&amp;#8217;ll probably remember that as &amp;#8220;siesta time&amp;#8221;. Everyone&amp;#8217;s energy level tends to be very low at that point of the day.&lt;/p&gt;
&lt;p&gt;So, thanks everyone for learning a bit about my new little project and to Mark for presenting my talk at that time and keeping the energy up.&lt;/p&gt;</description>
	<pubDate>Tue, 29 Jul 2008 20:32:53 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Nose and Decorators: be careful!</title>
	<guid>http://www.blueskyonmars.com/2008/07/25/nose-and-decorators-be-careful/</guid>
	<link>http://www.blueskyonmars.com/2008/07/25/nose-and-decorators-be-careful/</link>
	<description>&lt;p&gt;One theory of unit testing is that your tests should all be entirely independent. I&amp;#8217;ve heard that Google actually has a test runner that randomizes the order of the tests on each run, so you&amp;#8217;re guaranteed that they&amp;#8217;re independent (otherwise they fail).&lt;/p&gt;
&lt;p&gt;I want my test &lt;em&gt;files&lt;/em&gt; to be independent, but I find that having one test lead into another is often a good way to reuse fixture and avoid making my test fixture more complicated than it needs to be.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.somethingaboutorange.com/mrl/projects/nose/&quot;&gt;Nose&lt;/a&gt; (and &lt;a href=&quot;http://codespeak.net/py/dist/test.html&quot;&gt;py.test&lt;/a&gt;) make this really easy, because they run the tests in the order in which they appear in the file. (Note that if you&amp;#8217;re using Nose to run unittest.TestCases, those tests still run alphabetically as they do under Python&amp;#8217;s built-in test runner). The file order running of tests is very natural and leads to few surprises. It&amp;#8217;s very easy to make a string of tests that build up a nice, complicated fixture testing little pieces as they move along. I&amp;#8217;ll mention that &lt;em&gt;most&lt;/em&gt; of my tests will actually run just fine in any order, but I like being able to count on the order when it&amp;#8217;s handy to do so.&lt;/p&gt;
&lt;p&gt;All of that is a lead-in to my fun from today. I&amp;#8217;m using Fuzzyman&amp;#8217;s &lt;a href=&quot;http://www.voidspace.org.uk/python/mock.html&quot;&gt;Mock&lt;/a&gt; module to drop in stand-ins for things that are annoying to test. Mock comes with a handy @patch decorator that will replace the callable of your choice with a Mock on the way in, and restore it automatically on the way out. It works great and is really easy to use.&lt;/p&gt;
&lt;p&gt;I was thrown off for a bit today because I put a @patch on one of my test functions, and it started failing because a file that it expected to see did not exist! Removing the decorator brought the file back. That file was created in a test function earlier in the file.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re nodding knowingly at this point, you&amp;#8217;ve probably worked with decorators a fair bit before. I&amp;#8217;ve been known to use &lt;a href=&quot;http://docs.turbogears.org/1.0#controller-decorators&quot;&gt;more than my fair share of decorators&lt;/a&gt;. I&amp;#8217;ve found that while the syntax is great, some of the side effects can be really annoying. That&amp;#8217;s why &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/&quot;&gt;Paver&lt;/a&gt;&amp;#8217;s decorators aren&amp;#8217;t true decorators. They just register behavior rather than replacing the function object.&lt;/p&gt;
&lt;p&gt;So, what&amp;#8217;s the relationship between using a decorator and the file-based ordering of tests? To sort by file order, Nose looks at the test function&amp;#8217;s func_code.co_firstlineno. In the case of ,my test today, that was around 250. However, when I applied the patch decorator, the function was no longer my original function&amp;#8230; it was the function that Mock&amp;#8217;s decorator returned (the one that does the nifty swapping in and out of the Mock). That was around line 97 of mock.py.&lt;/p&gt;
&lt;p&gt;When Nose went to sort the functions by func_code.co_firstlineno, after decoration my test function was thought to be at line 97. I naively thought that I&amp;#8217;d just change func_code.co_firstlineno. Nope, read only. Then I tried sticking an object in place of func_code that returned the value I wanted for co_firstlineno. Nope, func_code &lt;em&gt;has&lt;/em&gt; to be a &amp;#8216;code&amp;#8217; object.&lt;/p&gt;
&lt;p&gt;Luckily, Nose itself has a solution to this problem. The function object can have a &amp;#8216;compat_co_firstlineno&amp;#8217; attribute on it, and that attribute will be used instead of func.func_code.co_firstlineno. A one-line change to mock.py was all it took.&lt;/p&gt;</description>
	<pubDate>Sat, 26 Jul 2008 03:50:58 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Robert Brewer: CherryPy for Python 3000</title>
	<guid>http://www.aminus.org/blogs/xmlsrv/989@http://www.aminus.org/blogs/</guid>
	<link>http://www.aminus.org/blogs/index.php/2008/07/25/cherrypy-for-python-3000?blog=2</link>
	<description>&lt;p&gt;I'm categorically rejecting the 2to3 approach--for myself anyway. If you think it would help, feel free to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&quot;upgrade&quot; CP to 2.6, which AFAICT means ensuring it will no longer work in 2.5 or previous versions&lt;/li&gt;
&lt;li&gt;turn on the 3k warning&lt;/li&gt;
&lt;li&gt;import-and-fix until you don't get any warnings&lt;/li&gt;
&lt;li&gt;run-tests-and-fix until you don't get any warnings&lt;/li&gt;
&lt;li&gt;run 2to3&lt;/li&gt;
&lt;li&gt;import-and-fix until you don't get any errors&lt;/li&gt;
&lt;li&gt;run-tests-and-fix until you don't get any errors&lt;/li&gt;
&lt;li&gt;wait for bug reports&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Me, I'd rather just drop cherrypy/ into 3k and skip steps 1-5.&lt;/p&gt;

&lt;p&gt;Changes I had to make so far (http://www.cherrypy.org/changeset/2029):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(4) urlparse -&gt; urllib.parse&lt;/li&gt;
&lt;li&gt;(24) &quot;except (ExcA, ExcB):&quot; -&gt; &quot;except ExcA, ExcB:&quot;&lt;/li&gt;
&lt;li&gt;(30) &quot;except ExcClass, x:&quot; -&gt; &quot;except ExcClass as x&quot;&lt;/li&gt;
&lt;li&gt;(22) u&quot;&quot; -&gt; &quot;&quot;&lt;/li&gt;
&lt;li&gt;(1) BaseHTTPServer -&gt; http.server&lt;/li&gt;
&lt;li&gt;(1) rfc822 -&gt; email.utils&lt;/li&gt;
&lt;li&gt;(4) md5.new() -&gt; hashlib.md5()&lt;/li&gt;
&lt;li&gt;(3) sha.new() -&gt; hashlib.sha1()&lt;/li&gt;
&lt;li&gt;(3) urllib2 -&gt; urllib&lt;/li&gt;
&lt;li&gt;(28) StringIO -&gt; io&lt;/li&gt;
&lt;li&gt;(1) func.func_code -&gt; func.&lt;strong&gt;code&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;(6) Cookie -&gt; http.cookies&lt;/li&gt;
&lt;li&gt;(3) ConfigParser -&gt; configparser&lt;/li&gt;
&lt;li&gt;(1) rfc822._monthnames -&gt; email._parseaddr._monthnames&lt;/li&gt;
&lt;li&gt;(105) print -&gt; print()&lt;/li&gt;
&lt;li&gt;(35) httplib -&gt; http.client&lt;/li&gt;
&lt;li&gt;(22) basestring -&gt; (str, bytes)&lt;/li&gt;
&lt;li&gt;(12) items() -&gt; list(items())&lt;/li&gt;
&lt;li&gt;(46) iteritems() -&gt; items()&lt;/li&gt;
&lt;li&gt;(11) Thread.get/setName -&gt; get/set_name&lt;/li&gt;
&lt;li&gt;(1) exec &quot;&quot; -&gt; exec(&quot;&quot;)&lt;/li&gt;
&lt;li&gt;(1) 0777 -&gt; 0o777&lt;/li&gt;
&lt;li&gt;(1) Queue -&gt; queue&lt;/li&gt;
&lt;li&gt;(1) urllib.unquote -&gt; urllib.parse.unquote&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the moment, I'm a bit blocked importing wsgiserver--we had a nonblocking version of makefile that subclassed the old socket._fileobject class. Looks like the whole socket implementation has changed (and much of it pushed down into C). Not looking forward to reimplementing that.&lt;/p&gt;
&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://www.aminus.org/blogs/index.php/2008/07/25/cherrypy-for-python-3000?blog=2&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
	<pubDate>Fri, 25 Jul 2008 18:00:07 +0000</pubDate>
	<dc:creator>fumanchu</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Sorry, Planet Python folks</title>
	<guid>http://www.blueskyonmars.com/2008/07/17/sorry-planet-python-folks/</guid>
	<link>http://www.blueskyonmars.com/2008/07/17/sorry-planet-python-folks/</link>
	<description>&lt;p&gt;I tend to watch the &lt;a href=&quot;http://planetpython.org/&quot;&gt;Unofficial Planet Python&lt;/a&gt; rather than &lt;a href=&quot;http://planet.python.org/&quot;&gt;Planet Python&lt;/a&gt;. The Unofficial Planet Python was only getting my Python feed, which is good. The official one, however, is getting everything. I&amp;#8217;ve asked for this to be changed, so hopefully soon the official Planet Python will only be listing my posts that are actually related to Python.&lt;/p&gt;
&lt;p&gt;To make matters worse, WordPress seems to have decided that it doesn&amp;#8217;t want to email me the comments that were showing up on my del.icio.us and Twitter posts. Ugh. Thanks to Virgil Dupras who contacted me via other means to let me know about the quite reasonable backlash.&lt;/p&gt;
&lt;p&gt;Sorry for reducing the signal to noise ratio on Planet Python! This will be fixed soon.&lt;/p&gt;
&lt;p&gt;Finally, a note about cross-posting Twitter to Blue Sky On Mars. My initial rationale for doing so is that I&amp;#8217;d like to have all of my presence on the web routed to this site so that my data is ultimately in my control in some fashion. After having used Twitter a bit, and certainly seeing the &amp;#8220;half a conversation&amp;#8221; aspect of many of the posts, I don&amp;#8217;t actually want my tweets posted here. So, I&amp;#8217;ve turned that off.&lt;/p&gt;
&lt;p&gt;Posting my del.icio.us links here has value, and I&amp;#8217;ll keep doing that. They just won&amp;#8217;t show up on Planet Python once my feed URL is changed there.&lt;/p&gt;</description>
	<pubDate>Thu, 17 Jul 2008 14:42:21 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: MichiPUG this week: ZODB</title>
	<guid>http://www.blueskyonmars.com/2008/06/30/michipug-this-week-zodb/</guid>
	<link>http://www.blueskyonmars.com/2008/06/30/michipug-this-week-zodb/</link>
	<description>&lt;p&gt;The &lt;a href=&quot;http://groups.google.com/group/michipug/web/index-2&quot;&gt;Michigan Python Users Group (MichiPUG)&lt;/a&gt; monthly meeting is coming up this Thursday, July 3rd at 7PM. This month, I&amp;#8217;ll be speaking about the &lt;a href=&quot;http://wiki.zope.org/ZODB/FrontPage&quot;&gt;Zope Object Database (ZODB)&lt;/a&gt;. Unlike last month&amp;#8217;s meeting, where I led us in a random experiment with Google App Engine, I actually have &lt;a href=&quot;http://www.blazingthings.com/dev/zcatalog.html&quot;&gt;some&lt;/a&gt; &lt;a href=&quot;http://www.blueskyonmars.com/2005/06/18/zodb-vs-pysqlite-with-sqlobject/&quot;&gt;experience&lt;/a&gt; with the ZODB.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll be demonstrating use of the ZODB and will talk about concurrency, replication, packing, etc. If you&amp;#8217;re not familiar with the ZODB (and you&amp;#8217;re somewhere near Ann Arbor!), this is a useful topic to get to know, because the ZODB is great for a variety of situations.&lt;/p&gt;</description>
	<pubDate>Mon, 30 Jun 2008 11:57:46 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Feed testing… please ignore…</title>
	<guid>http://www.blueskyonmars.com/?p=2410</guid>
	<link>http://www.blueskyonmars.com/2008/06/23/feed-testing-please-ignore/</link>
	<description>&lt;p&gt;Sorry for the noise.&lt;/p&gt;</description>
	<pubDate>Mon, 23 Jun 2008 12:37:55 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Robert Brewer: Tracking memory leaks with Dowser</title>
	<guid>http://www.aminus.org/blogs/xmlsrv/980@http://www.aminus.org/blogs/</guid>
	<link>http://www.aminus.org/blogs/index.php/2008/06/11/tracking-memory-leaks-with-dowser?blog=2</link>
	<description>&lt;p&gt;Marius Gedminas just wrote &lt;a href=&quot;http://mg.pov.lt/blog/hunting-python-memleaks&quot;&gt;a post on memory leaks&lt;/a&gt;. He could have used &lt;a href=&quot;http://www.aminus.net/wiki/Dowser&quot;&gt;Dowser&lt;/a&gt; to find the leak more easily, I'll bet.&lt;/p&gt;

&lt;p&gt;Dowser is a CherryPy application for monitoring and managing object references in your Python program. Because CherryPy runs everything (even the listening HTTP socket) in its own threads, it's a snap to include Dowser in any Python process. Dowser is also very lightweight (because CherryPy is). Here's how I added it to a Twisted project we're using at work:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;...
from twisted.application import service
application = service.Application(&quot;My Server&quot;)
s.setServiceParent(application)

import cherrypy
from misc import dowser
cherrypy.config.update({'server.socket_port': 8088})
cherrypy.tree.mount(dowser.Root())
cherrypy.engine.autoreload.unsubscribe()
# Windows only
cherrypy._console_control_handler.unsubscribe()
cherrypy.engine.start()

from twisted.internet import reactor
reactor.addSystemEventTrigger('after', 'shutdown', cherrypy.engine.exit)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The lines before 'import cherrypy' already existed and are here just for context (this is a Twisted service.tac module). Let's quickly discuss the new code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;import cherrypy and dowser. You don't have to stick dowser into a 'misc' folder; that's just how I checked it out from svn.&lt;/li&gt;
&lt;li&gt;Set the port you want CherryPy to listen on; pick a port your app isn't already using if it's a TCP server.&lt;/li&gt;
&lt;li&gt;Mount the dowser root.&lt;/li&gt;
&lt;li&gt;Turn off the CherryPy autoreloader, and the Ctrl-C handler if you're on Windows. I should really turn that off by default in CP. :/&lt;/li&gt;
&lt;li&gt;Start the engine, which starts listening on the port in a new thread among other things.&lt;/li&gt;
&lt;li&gt;Tell Twisted to stop CherryPy when it stops.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then browse to &lt;a href=&quot;http://localhost:8088/&quot;&gt;http://localhost:8088/&lt;/a&gt; and you'll see pretty sparklines of all the objects. Change the URL to &lt;a href=&quot;http://localhost:8088/?floor=20&quot;&gt;http://localhost:8088/?floor=20&lt;/a&gt; to see graphs for only those objects which have 20 or more objects.&lt;/p&gt;

&lt;div class=&quot;image_block&quot;&gt;&lt;img src=&quot;http://www.aminus.org/blogs/media/blogs/fumanchu/dowserindex.gif&quot; alt=&quot;&quot; title=&quot;&quot; width=&quot;538&quot; height=&quot;275&quot; /&gt;&lt;/div&gt;

&lt;p&gt;Then, just click on the 'TRACE' links to get &lt;em&gt;lots&lt;/em&gt; more information about each object. See the Dowser &lt;a href=&quot;http://www.aminus.net/wiki/Dowser&quot;&gt;wiki page&lt;/a&gt; for more details and screenshots.&lt;/p&gt;
&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://www.aminus.org/blogs/index.php/2008/06/11/tracking-memory-leaks-with-dowser?blog=2&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
	<pubDate>Thu, 12 Jun 2008 03:00:12 +0000</pubDate>
	<dc:creator>fumanchu</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: “Why Do I need To Sign This?” : Alex Russell on contributor agreements</title>
	<guid>http://www.blueskyonmars.com/2008/06/11/%e2%80%9cwhy-do-i-need-to-sign-this%e2%80%9d-alex-russell-on-contributor-agreements/</guid>
	<link>http://www.blueskyonmars.com/2008/06/11/%e2%80%9cwhy-do-i-need-to-sign-this%e2%80%9d-alex-russell-on-contributor-agreements/</link>
	<description>&lt;p&gt;Anyone who runs a significant open source project should read this, especially if you don&amp;#8217;t currently require your contributors to send in any kind of agreement:&lt;/p&gt;
&lt;blockquote cite=&quot;http://alex.dojotoolkit.org/?p=679&quot;&gt;&lt;p&gt;
  &lt;br /&gt;
  So why have it? Why create the barrier to entry for newcomers who just want to pitch in? I have great sympathy for the impatient potential contributor huffing “why do I need to sign this, anyway?”, so this blog post is an effort to boil it down.&lt;br /&gt;
  [From &lt;a href=&quot;http://alex.dojotoolkit.org/?p=679&quot;&gt;&lt;cite&gt;“Why Do I need To Sign This?”&lt;/cite&gt;&lt;/a&gt;]
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;I&amp;#8217;ve spoken with Alex a couple of times about open source intellectual property, and he&amp;#8217;s definitely given this a lot of thought. For a project the size of Dojo, involving many very large contributors, having something like Dojo&amp;#8217;s CLA seems critical for keeping the IP clean.&lt;/p&gt;
&lt;p&gt;With TurboGears, from the beginning, I&amp;#8217;ve required people to send in a simple contributor agreement and this sums up why: &amp;#8220;One of the best aspects of the CLA process is that it gets people who are contributing to think about what it means to contribute.&amp;#8221;. Significant open source projects that people depend on need to have contributors that are serious about maintaining the project&amp;#8217;s quality &lt;span&gt;and&lt;/span&gt; the project&amp;#8217;s IP. Making people aware of this responsibility from the get-go is a big positive.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m posting this in hopes that more of my friends in open source software will keep these things in mind as their projects grow and the outside code contributions increase.&lt;/p&gt;</description>
	<pubDate>Wed, 11 Jun 2008 15:52:10 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Easy, Repeatable Building/Deployment of Python+Dojo Projects</title>
	<guid>http://www.blueskyonmars.com/?p=2400</guid>
	<link>http://www.blueskyonmars.com/2008/06/05/easy-repeatable-buildingdeployment-of-pythondojo-projects/</link>
	<description>&lt;p&gt;My latest substantial blog post is now up: &lt;a href=&quot;http://www.sitepen.com/blog/2008/06/05/easy-repeatable-buildingdeployment-of-pythondojo-projects/&quot;&gt;SitePen Blog  » Easy, Repeatable Building/Deployment of Python+Dojo Projects&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;a href=&quot;http://dojotoolkit.org&quot;&gt;Dojo&lt;/a&gt; on the client and &lt;a href=&quot;http://python.org/&quot;&gt;Python&lt;/a&gt; on the server make for a great combination. They&amp;#8217;re easy, productive and powerful. In this article, I&amp;#8217;ll show you how to use Python + Dojo to cut the number of requests to your server by 95% and simplify development and deployment while you&amp;#8217;re at it.&lt;/p&gt;
&lt;/blockquote&gt;</description>
	<pubDate>Thu, 05 Jun 2008 12:33:37 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: MichiPUG on Thursday: Google App Engine</title>
	<guid>http://www.blueskyonmars.com/2008/06/03/michipug-on-thursday-google-app-engine/</guid>
	<link>http://www.blueskyonmars.com/2008/06/03/michipug-on-thursday-google-app-engine/</link>
	<description>&lt;p&gt;We&amp;#8217;ve settled on a topic for the coming &lt;a href=&quot;http://groups.google.com/group/michipug/web/index-2&quot;&gt;Michigan Python Users Group&lt;/a&gt; meeting: &lt;a href=&quot;http://code.google.com/appengine/&quot;&gt;Google App Engine&lt;/a&gt;. We do not have a speaker, so this will be a combination of discussion and exploration. I have written some App Engine code, and I&amp;#8217;m guessing that others that will be attending have, too, so it&amp;#8217;s not all trial-and-error.&lt;/p&gt;
&lt;p&gt;Following our usual formal (first Thursday of the month), the meeting will be on June 5th at 7PM at &lt;a href=&quot;http://srtsolutions.com/&quot;&gt;SRT Solutions&lt;/a&gt; in downtown Ann Arbor. There are parking structures nearby (4th and Washington and Liberty Square are both close), and there is usually free street parking on Ann Street near the police station.&lt;/p&gt;
&lt;p&gt;See you there!&lt;/p&gt;</description>
	<pubDate>Tue, 03 Jun 2008 14:36:03 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: TurboGears Web Services gets a new maintainer</title>
	<guid>http://www.blueskyonmars.com/?p=2389</guid>
	<link>http://www.blueskyonmars.com/2008/05/22/turbogears-web-services-gets-a-new-maintainer/</link>
	<description>&lt;p&gt;Justin Davis has just announced that &lt;a href=&quot;http://groups.google.com/group/turbogears-web-services/browse_frm/thread/5bcf140e113b77ac?hl=en&quot;&gt;Christophe de Vienne&lt;/a&gt; is the new maintainer of the TurboGears Web Services (TGWS) project. Thank you Christophe for carrying this project forward! I consider it a good sign for a project&amp;#8217;s health when it can make the transition between maintainers, which is something both TurboGears and TGWS have done.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://code.google.com/p/tgws/&quot;&gt;TGWS&lt;/a&gt;, if you&amp;#8217;re not familiar with it, is a multiprotocol web services extension for TurboGears 1.&lt;/p&gt;</description>
	<pubDate>Thu, 22 May 2008 11:36:50 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Paver 0.8: new options features, doctools features and bug fixes</title>
	<guid>http://www.blueskyonmars.com/2008/05/20/paver-08-new-options-features-doctools-features-and-bug-fixes/</guid>
	<link>http://www.blueskyonmars.com/2008/05/20/paver-08-new-options-features-doctools-features-and-bug-fixes/</link>
	<description>&lt;p&gt;For various reasons, I released &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/&quot;&gt;Paver&lt;/a&gt; 0.7.3 on Friday and Paver 0.8 yesterday. I have an idea of what the coming 1.0&amp;#8217;s zc.buildout integration will be like, and I think it will be quite cool and useful.&lt;/p&gt;
&lt;p&gt;In the meantime, though, I&amp;#8217;ve got some new features that set the stage for things I need to do in 1.0. Specifically, you can now pass in a dictionary in your options search ordering. So, you can pull options from any source you&amp;#8217;ve got at the time the task is running and stick them at the front of the line. I expect to use this in buildout options handling.&lt;/p&gt;
&lt;p&gt;A nice new feature is the ability to set options on the command line. You can do something like:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;
paver some.option=hello task1 some.option=goodbye task2
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Doing that, paver will set some.option to hello, run task1 and then change the option to goodbye before running task2.&lt;/p&gt;
&lt;p&gt;The new cog.include_markers and cog.delete_code options allow you to remove Cog&amp;#8217;s markers from the output and instead put a nicer bit of text to say where the snippet of code came from. Letting the user know where a sample code snippet came from is quite valuable, so I want to make it possible to do so in as pleasing a way as possible.&lt;/p&gt;
&lt;p&gt;For &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/getting_started.html&quot;&gt;Paver&amp;#8217;s Getting Started Guide&lt;/a&gt;, I ended up not using the new include_markers feature and instead just changed the Cog delimiters. I did this because Paver runs shell commands in addition to including file sections when generating the docs. I wanted those shell commands to be included. I think the new markers are more pleasant to look at, and I&amp;#8217;ll be curious to get feedback since I heard from more than one person that the Cog delimiters looked like they were left in by mistake.&lt;/p&gt;
&lt;p&gt;Paver is starting to get some traction as it has picked up its first patches from outsiders, and I&amp;#8217;ve started to get some feedback on breakage from Windows users (fixed in 0.8). &lt;a href=&quot;http://compoundthinking.com/blog/&quot;&gt;Mark&lt;/a&gt; let me put Paver into &lt;a href=&quot;http://compoundthinking.com/tg2/&quot;&gt;TurboGears 2&lt;/a&gt;, and I think it will help out there, so that will introduce quite a number more people to the project. As always, come and &lt;a href=&quot;http://groups.google.com/group/paver/&quot;&gt;join us on the mailing list&lt;/a&gt; if you have any questions or problems!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.6&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=Paver+0.8%3A+new+options+features%2C+doctools+features+and+bug+fixes&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F05%2F20%2Fpaver-08-new-options-features-doctools-features-and-bug-fixes%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 21 May 2008 02:28:39 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Paver 0.7: Better than distutils, better docs and much more</title>
	<guid>http://www.blueskyonmars.com/2008/05/07/paver-07-better-than-distutils-better-docs-and-much-more/</guid>
	<link>http://www.blueskyonmars.com/2008/05/07/paver-07-better-than-distutils-better-docs-and-much-more/</link>
	<description>&lt;p&gt;I&amp;#8217;m delighted to release &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/&quot;&gt;Paver&lt;/a&gt; 0.7. If you missed my &lt;a href=&quot;http://www.blueskyonmars.com/2008/04/22/paver-and-the-building-distribution-deployment-etc-of-python-projects/&quot;&gt;original announcement&lt;/a&gt;, the short story is that Paver is a new build, distribution and deployment scripting tool geared toward Python projects. My original announcement and the &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/foreword.html&quot;&gt;new foreword&lt;/a&gt; to the docs explain the motivation.&lt;/p&gt;
&lt;p&gt;Ben Bangert and others pointed out a giant documentation bug in 0.4: there was a fair bit of reference doc but no doc that said &amp;#8220;here&amp;#8217;s how you get started with Paver&amp;#8221;. Now there is: Paver&amp;#8217;s &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/getting_started.html#gettingstarted&quot;&gt;Getting Started Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Paver 0.7 is a big step up from 0.4 (hence the version number bump). I implemented one of the two major features I had planned for 1.0: distutils/setuptools integration. It&amp;#8217;s really cool. Have you ever wanted to just slightly change how &amp;#8220;sdist&amp;#8221; or &amp;#8220;upload&amp;#8221; or &amp;#8220;develop&amp;#8221; worked? Now you can, just by writing a function in your pavement.py file. And don&amp;#8217;t worry, you don&amp;#8217;t need to duplicate anything between setup.py and pavement.py. It all just moves into pavement.py and Paver can even generate a setup.py file for you, since most people are use to the common &amp;#8220;python setup.py install&amp;#8221; command.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve gone even farther than that with making it easy to use Paver and not annoy users that don&amp;#8217;t yet have Paver. Paver can create a small zip file of Paver&amp;#8217;s core bits so that &amp;#8220;python setup.py install&amp;#8221; will work just fine even for users who don&amp;#8217;t have Paver installed. Paver can also create a virtualenv bootstrap script for you, so that users don&amp;#8217;t necessarily need to install your package on their systems in order to use it.&lt;/p&gt;
&lt;p&gt;Paver&amp;#8217;s got new documentation tools that work great with Sphinx. It&amp;#8217;s now easy to mark sections of sample code files and then include those sections in your documentation, using the built-in version of Ned Batchelder&amp;#8217;s &lt;a href=&quot;http://nedbatchelder.com/code/cog/index.html&quot;&gt;Cog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And I&amp;#8217;m definitely eating my own dogfood. Paver is built using Paver itself and the source distribution includes the paver-minilib so that setup.py install should work fine (let me know if it doesn&amp;#8217;t!) The new Getting Started Guide uses the new documentation tools.&lt;/p&gt;
&lt;p&gt;There are even more changes than these, and you can look at the &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/changelog.html#may-7-2008&quot;&gt;changelog&lt;/a&gt; for the full list. Note that if you&amp;#8217;re using Paver 0.4, there are a couple of trivial breaking changes.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.6&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=Paver+0.7%3A+Better+than+distutils%2C+better+docs+and+much+more&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F05%2F07%2Fpaver-07-better-than-distutils-better-docs-and-much-more%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Thu, 08 May 2008 02:55:29 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: simplejson heading for the stdlib</title>
	<guid>http://www.blueskyonmars.com/2008/05/04/simplejson-heading-for-the-stdlib/</guid>
	<link>http://www.blueskyonmars.com/2008/05/04/simplejson-heading-for-the-stdlib/</link>
	<description>&lt;p&gt;Seeing this on Bob Ippolito&amp;#8217;s blog might seem a little odd to many:&lt;/p&gt;
&lt;blockquote cite=&quot;http://bob.pythonmac.org/archives/2008/05/03/simplejson-19/&quot;&gt;&lt;p&gt;
  Rewrote test suite with unittest and doctest (no more nosetest dependency)&lt;br /&gt;
  [From &lt;a href=&quot;http://bob.pythonmac.org/archives/2008/05/03/simplejson-19/&quot;&gt;&lt;cite&gt;simplejson 1.9&lt;/cite&gt;&lt;/a&gt;]
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Why on Earth would someone change from nose-style tests to unittest tests? How about so that the library can &lt;a href=&quot;http://bugs.python.org/issue2750&quot;&gt;go into the Python Standard Library&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;simplejson will be a great addition. Thanks to Bob and the others who are working to get simplejson in!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.6&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=simplejson+heading+for+the+stdlib&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F05%2F04%2Fsimplejson-heading-for-the-stdlib%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Mon, 05 May 2008 02:06:34 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: MichiPUG on Thursday: zc.buildout and Paver</title>
	<guid>http://www.blueskyonmars.com/2008/04/28/michipug-on-thursday-zcbuildout-and-paver/</guid>
	<link>http://www.blueskyonmars.com/2008/04/28/michipug-on-thursday-zcbuildout-and-paver/</link>
	<description>&lt;p&gt;The May Michigan Python Users Group (MichiPUG) meeting is coming up on Thursday, May 1. I&amp;#8217;ll be leading discussion on &lt;a href=&quot;http://pypi.python.org/pypi/zc.buildout/1.0.1&quot;&gt;zc.buildout&lt;/a&gt; and &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/&quot;&gt;Paver&lt;/a&gt;. Any build/distribution/deployment tool talk is welcome, as well as our usual general talk about Python topics.&lt;/p&gt;
&lt;p&gt;I hope to see you &lt;a href=&quot;http://groups.google.com/group/michipug/web/SRT%20Solutions&quot;&gt;there&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5.1&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=MichiPUG+on+Thursday%3A+zc.buildout+and+Paver&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F04%2F28%2Fmichipug-on-thursday-zcbuildout-and-paver%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Mon, 28 Apr 2008 15:49:08 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Paver and the building, distribution, deployment etc. of Python projects</title>
	<guid>http://www.blueskyonmars.com/2008/04/22/paver-and-the-building-distribution-deployment-etc-of-python-projects/</guid>
	<link>http://www.blueskyonmars.com/2008/04/22/paver-and-the-building-distribution-deployment-etc-of-python-projects/</link>
	<description>&lt;p&gt;This morning, I released a new open source &amp;#8220;build tool&amp;#8221; aimed at Python projects: Paver. The goal of Paver is to provide a smooth way to script up the management of your Python projects. You can read all about it on the &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/&quot;&gt;Paver site&lt;/a&gt;, but I wanted to provide some background here.&lt;/p&gt;
&lt;h2&gt;Look at all these tools!&lt;/h2&gt;
&lt;p&gt;Python programmers have a great many tools at our disposal. We have tons of libraries that make it so that we don&amp;#8217;t have to write lots of code to get our software built. We also have a broad collection of tools to help us manage our projects.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Python&amp;#8217;s standard library includes &lt;a href=&quot;http://docs.python.org/lib/module-distutils.html&quot;&gt;distutils&lt;/a&gt;, for packaging up and distributing Python projects.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://peak.telecommunity.com/DevCenter/setuptools&quot;&gt;setuptools&lt;/a&gt; is almost part of the standard library, and quite a few projects require it. setuptools gives you cross-platform dependency management, more packaging options, script generation and a simple plugin framework.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://pypi.python.org/pypi/zc.buildout&quot;&gt;zc.buildout&lt;/a&gt; helps you with the creation of repeatable, easily installed ready-to-run installations of projects. It gives you a contained environment so that you don&amp;#8217;t need to muck with the global Python configuration on the system to make a working installation.&lt;/li&gt;
&lt;li&gt;zc.buildout supports &lt;a href=&quot;http://pypi.python.org/pypi?%3Aaction=search&amp;amp;term=buildout+recipe&amp;amp;submit=search&quot;&gt;&amp;#8220;recipes&amp;#8221;&lt;/a&gt; that handle installation and configuration of various parts that your Python project may need&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://pypi.python.org/pypi/virtualenv&quot;&gt;virtualenv&lt;/a&gt; gives you just the contained installation part of zc.buildout, but it does it in a slightly different way that I&amp;#8217;ve found easier for certain, not-egg-friendly projects.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://pythonpaste.org/script/&quot;&gt;PasteScript&lt;/a&gt; can be used to generate configuration files and complete skeleton projects&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sphinx.pocoo.org/&quot;&gt;Sphinx&lt;/a&gt; is a new package for generating documentation from ReStructred Text sources. It&amp;#8217;s very cool, and it&amp;#8217;s what I used for Paver&amp;#8217;s site.&lt;/li&gt;
&lt;li&gt;and there are many, many more&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Seems great, what&amp;#8217;s the problem?&lt;/h2&gt;
&lt;p&gt;I have personally used all of these tools at one time or another. In fact, I&amp;#8217;ve used them all recently. In working with them, I couldn&amp;#8217;t help but notice some aspects that made my life harder than it needed be.&lt;/p&gt;
&lt;p&gt;For example, when using distutils or setuptools, it&amp;#8217;s very easy to add behavior that runs before or after the setup command, because your setup files are just plain Python. It&amp;#8217;s not as easy to customize the way a command behaves, or to add a new command entirely. You need to read the docs, make a new class and register that class somehow.&lt;/p&gt;
&lt;p&gt;zc.buildout is awesome and makes it easy to get a predictable collection of components installed. It uses an INI file as its file format, which means that adding behavior is not straightforward. Creating a new zc.buildout recipe is very much like creating a new setuptools command: create a separate class and refer to it an in egg. I believe there&amp;#8217;s a zc.buildout recipe for putting some commands in your INI file. Do you want Python code in your INI file?&lt;/p&gt;
&lt;p&gt;Which also brings up another point: distutils and setuptools use a Python file and keyword parameters for their configuration. (There is also an optional INI file.) zc.buildout uses an INI file. Sphinx uses a .py file.&lt;/p&gt;
&lt;h2&gt;What would I want?&lt;/h2&gt;
&lt;p&gt;It seemed to me that life would be better if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If I need to do something that takes 5 lines of Python, I could do it in little more than 5 lines of Python without adding another file for that purpose.&lt;/li&gt;
&lt;li&gt;If configuration could take on a consistent, predictable form&lt;/li&gt;
&lt;li&gt;If things that I do often in managing my projects took even less Python to script.&lt;/li&gt;
&lt;li&gt;If the system could be used easily with multiple projects by not requiring anything else, but taking advantage of other packages when they&amp;#8217;re present&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is with those goals and looking around that Paver came into existence. As with TurboGears, I did not want to reinvent the various parts of the whole that I&amp;#8217;m angling for. The idea is to use zc.buildout&amp;#8217;s machinery, not reinvent it. I used Jason Orendorff&amp;#8217;s great path.py module rather than inventing my own abstraction there.&lt;/p&gt;
&lt;p&gt;I didn&amp;#8217;t set out to invent the scripting format, either. I seriously considered Zed Shaw&amp;#8217;s &lt;a href=&quot;http://www.zedshaw.com/projects/vellum/&quot;&gt;Vellum&lt;/a&gt; which has shaped up quite nicely. But in trying it out, I realized that I really wanted my projects managed by Python scripts that had little headache and little overhead. Doing computations, loops and breaking code up into separate functions (or other organizing blocks) are all obvious for a Python programmer if the language is Python. For the record, Zed wants his build files to be just &amp;#8220;data&amp;#8221;, for perfectly rational reasons. For me, though, I want Python.&lt;/p&gt;
&lt;p&gt;Now for the &amp;#8220;this is an &lt;strong&gt;early release caveat&lt;/strong&gt;&amp;#8220;. Paver is functional, and I use it. But, its support for the various libraries is quite shallow right now, and zc.buildout/virtualenv are not at all represented yet. What I&amp;#8217;ve released is basically the parts that I&amp;#8217;ve needed so far, and I&amp;#8217;ll be adding on as I need things. I figured that if others think the approach is worthwhile, we can pool our efforts and build out the &lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/paverstdlib.html&quot;&gt;Paver Standard Library&lt;/a&gt; a bit quicker. I should also note that while Paver should work on Windows, it&amp;#8217;s only been used on Macs and Linux. Finally, it&amp;#8217;s possible that Paver&amp;#8217;s pavement.py syntax may change along the way to 1.0, but I can promise to document those changes and I don&amp;#8217;t expect a great deal of pain in making the transitions.&lt;/p&gt;
&lt;p&gt;Note also that if you maintain a Python library that is useful in helping people work with the projects, it&amp;#8217;s easy to add Paver targets and such to your own library. Paver itself includes support for other libraries because of the chicken-and-egg problem. People won&amp;#8217;t support Paver until people are using it and people wouldn&amp;#8217;t use it if it didn&amp;#8217;t support the kinds of things that people already do. So, Paver includes the connectors for the libraries that I need.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve set up all of the various project goodies for Paver:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.blueskyonmars.com/projects/paver/index.html&quot;&gt;Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://launchpad.net/paver/&quot;&gt;Launchpad project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Public bzr branch:&lt;br /&gt;
  &lt;span&gt;&lt;span&gt;&lt;span class=&quot;pre&quot;&gt;bzr&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;branch&lt;/span&gt; ht&lt;span class=&quot;pre&quot;&gt;tp://bazaar.launchpad.net/~dangoor/paver/main&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;a href=&quot;http://groups.google.com/group/paver&quot;&gt;Mailing list&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ian Bicking has given me a great mass of useful feedback, which I have not yet fully digested. Mark Ramm, Ben Bangert and David Stanek also had some helpful input.&lt;/p&gt;
&lt;p&gt;And, I&amp;#8217;d love to hear more from &lt;span&gt;you&lt;/span&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5.1&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=Paver+and+the+building%2C+distribution%2C+deployment+etc.+of+Python+projects&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F04%2F22%2Fpaver-and-the-building-distribution-deployment-etc-of-python-projects%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 22 Apr 2008 16:45:48 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Amazon preannounces persistent storage for EC2</title>
	<guid>http://www.blueskyonmars.com/2008/04/14/amazon-preannounces-persistent-storage-for-ec2/</guid>
	<link>http://www.blueskyonmars.com/2008/04/14/amazon-preannounces-persistent-storage-for-ec2/</link>
	<description>&lt;p&gt;I don&amp;#8217;t know if this preannouncement comes as a result of all of the Google App Engine publicity, but here it is: &lt;a href=&quot;http://aws.typepad.com/aws/2008/04/block-to-the-fu.html&quot;&gt;Amazon Web Services Blog: Storage Space, The Final Frontier&lt;/a&gt;. In a nutshell: AWS now lets you create a storage volume of 1GB to 1TB  that can be mounted in one EC2 instance and will persist beyond the lifetime of an EC2 instance. As an added bonus, you can have automatic snapshots of your volume plunked into S3.&lt;/p&gt;
&lt;p&gt;They say that this storage is a low-latency, high-throughput block device. So, you can run all kinds of traditional software on top of it.&lt;/p&gt;
&lt;p&gt;This will change the competitive outlook a bit between AWS and GAE a bit, because it makes it easier for people to use all of the software pieces that they&amp;#8217;re used to when they use AWS to manage the hardware infrastructure. This means that it&amp;#8217;s easier to take your existing apps and skills and get them up on AWS. GAE has a fight ahead in terms of getting people to write their apps differently&amp;#8230; but the benefit to doing so is that you no longer think of hardware infrastructure at all.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5.1&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=Amazon+preannounces+persistent+storage+for+EC2&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F04%2F14%2Famazon-preannounces-persistent-storage-for-ec2%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Mon, 14 Apr 2008 13:34:16 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: App Engine: I agree with Ian Bicking the Luddite</title>
	<guid>http://www.blueskyonmars.com/2008/04/09/app-engine-i-agree-with-ian-bicking-the-luddite/</guid>
	<link>http://www.blueskyonmars.com/2008/04/09/app-engine-i-agree-with-ian-bicking-the-luddite/</link>
	<description>&lt;p&gt;Isn&amp;#8217;t quoting out of context great:&lt;/p&gt;
&lt;blockquote cite=&quot;http://blog.ianbicking.org/2008/04/09/app-engine-commodity-vs-proprietary/&quot;&gt;&lt;p&gt;
  I hate computers.&lt;br /&gt;
  [From &lt;a href=&quot;http://blog.ianbicking.org/2008/04/09/app-engine-commodity-vs-proprietary/&quot;&gt;&lt;cite&gt;Ian Bicking: App Engine: Commodity vs. Proprietary&lt;/cite&gt;&lt;/a&gt;]
&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;More seriously, though, in saying &amp;#8220;I hate computers&amp;#8221;, Ian is actually talking about the opposite of being a Luddite. He&amp;#8217;s dreaming of a world in which much of computing just works in the background, so that we can spend our time doing more important and interesting things in the foreground.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m linking to Ian here because he&amp;#8217;s said exactly what I have been thinking about &lt;a href=&quot;http://appengine.google.com/&quot;&gt;App Engine&lt;/a&gt;: from a Python programming perspective the APIs are simple and clear. I can easily imagine a ZODB-based implementation of Google&amp;#8217;s data store API. Just change your imports, and you can be off of Google&amp;#8217;s infrastructure and on to your own.&lt;/p&gt;
&lt;p&gt;Of course, for a great many people there won&amp;#8217;t be any reason to be off of Google&amp;#8217;s infrastructure. App Engine is just &lt;span&gt;so darn easy&lt;/span&gt;. Amazon Web Services is impressive because it makes scalability affordable and available. App Engine interests me because, for its broad-but-still-limited set of use cases, it makes scalability a no brainer. &amp;#8220;Build your app like this, and you never have to think of scaling&amp;#8221; is a nice thought. I&amp;#8217;ve been around enough to know that people using App Engine will still have to think of scaling &lt;span&gt;some&lt;/span&gt;, but not nearly as much as with just about any other solution.&lt;/p&gt;
&lt;p&gt;Back to the lock-in aspect, though. I still see App Engine as likely to be utterly unsuccessful with large businesses. That is, until a new Google Appliance comes out. I&amp;#8217;ve been predicting such a beast since Google Docs was first introduced, and I think App Engine makes it all the more likely. I still believe that there will come a time when Google will sell boxes to big companies that those companies can toss into some racks on their networks and deploy App Engine apps locally, as well as run Google Docs on their private nets. Things will get even more interesting at that point.&lt;/p&gt;
&lt;p&gt;You can bet that Amazon is studying App Engine closely and considering their own high-level service as I write this. From a developer&amp;#8217;s perspective, this competition is going to be awesome.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5.1&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=App+Engine%3A+I+agree+with+Ian+Bicking+the+Luddite&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F04%2F09%2Fapp-engine-i-agree-with-ian-bicking-the-luddite%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Thu, 10 Apr 2008 01:17:48 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Google App Engine, not really an AWS competitor?</title>
	<guid>http://www.blueskyonmars.com/2008/04/08/google-app-engine-not-really-an-aws-competitor/</guid>
	<link>http://www.blueskyonmars.com/2008/04/08/google-app-engine-not-really-an-aws-competitor/</link>
	<description>&lt;p&gt;It occurred to me just now that Google App Engine and Amazon Web Services are only barely in competition right now. If you want an infinite storage system like AWS S3 in App Engine, you need to code it yourself (ignoring the preview limits App Engine currently has). If you want to deploy apps as easily as you can with App Engine in AWS, you need a bunch of infrastructure that AWS does not provide.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m happy to see that App Engine&amp;#8217;s datastore is transactional, unlike SimpleDB. I didn&amp;#8217;t see anything in my skim of some docs about whether App Engine has eventual consistency or if you can immediately pull out data that you stuff in. My guess is that you can immediately pull out the data you shove in. This is a win over SimpleDB, in my opinion.&lt;/p&gt;
&lt;p&gt;App Engine is just tons higher-level than AWS. Of course, you can host anything you want in AWS. But, by trading away a bunch of that flexibility, Google has made a service that allows people to build apps that scale well with a minimum of fuss.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5.1&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=Google+App+Engine%2C+not+really+an+AWS+competitor%3F&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F04%2F08%2Fgoogle-app-engine-not-really-an-aws-competitor%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 08 Apr 2008 11:09:25 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Google App Engine - big apps for Python folks</title>
	<guid>http://www.blueskyonmars.com/2008/04/08/google-app-engine-big-apps-for-python-folks/</guid>
	<link>http://www.blueskyonmars.com/2008/04/08/google-app-engine-big-apps-for-python-folks/</link>
	<description>&lt;p&gt;Google&amp;#8217;s App Engine has been released. This is much cooler than just opening up BigTable for outside access (which is what TechCrunch reported over the weekend). One big difference between App Engine and Amazon Web Services is that the &lt;a href=&quot;http://code.google.com/appengine/docs/gettingstarted/devenvironment.html&quot;&gt;The Development Environment&lt;/a&gt; lets you build an app locally, including Google&amp;#8217;s auth API and datastore. That&amp;#8217;s very clever. You can build up an app completely and then deploy it when ready.&lt;/p&gt;
&lt;p&gt;Or, in the case of the preview period, when you get an account&amp;#8230; which, sadly, I didn&amp;#8217;t. I rather wish there was a bit more information about when more developer slots will be opened. It would be a shame to create a cool app and have to sit on it for months. It would also be nice to know what pricing will look like, but given what they are giving away for free, I&amp;#8217;m guessing it will not be unreasonable.&lt;/p&gt;
&lt;p&gt;Overall, I&amp;#8217;ve got to say that it looks like a great service on the surface.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5.1&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=Google+App+Engine+-+big+apps+for+Python+folks&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F04%2F08%2Fgoogle-app-engine-big-apps-for-python-folks%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 08 Apr 2008 10:43:35 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Rumor: Google To Launch BigTable As Web Service</title>
	<guid>http://www.blueskyonmars.com/2008/04/05/rumor-google-to-launch-bigtable-as-web-service/</guid>
	<link>http://www.blueskyonmars.com/2008/04/05/rumor-google-to-launch-bigtable-as-web-service/</link>
	<description>&lt;p&gt;Interesting rumor, and totally plausible. Just as Amazon has thought &amp;#8220;why not make some money off of all of this great infrastructure we&amp;#8217;ve built&amp;#8221;, it looks like Google is going to do the same thing: &lt;a href=&quot;http://www.techcrunch.com/2008/04/04/source-google-to-launch-bigtable-as-web-service/&quot;&gt;Source: Google To Launch BigTable As Web Service&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Google may be releasing BigTable, its internal database system, as a web service to compete with Amazon SimpleDB, according to a source with knowledge of the launch.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;This will be one more non-traditional database among the many interesting choices that exist today.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5.1&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=Rumor%3A+Google+To+Launch+BigTable+As+Web+Service&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F04%2F05%2Frumor-google-to-launch-bigtable-as-web-service%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Sun, 06 Apr 2008 02:12:33 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: InternetNews - Python Fans Take Aim at the Enterprise</title>
	<guid>http://www.blueskyonmars.com/2008/04/04/internetnews-python-fans-take-aim-at-the-enterprise/</guid>
	<link>http://www.blueskyonmars.com/2008/04/04/internetnews-python-fans-take-aim-at-the-enterprise/</link>
	<description>&lt;p&gt;David Goodger, Michael Foord and I talk about Python&amp;#8217;s enterpriseyness in &lt;a href=&quot;http://www.internetnews.com/dev-news/article.php/3738856&quot;&gt;InternetNews Realtime IT News – Python Fans Take Aim at the Enterprise&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;After years in the shadows, the open source Python programming language is becoming increasingly mainstream. There are more users and more tools. Backers of Python now argue that Python is ready for the enterprise.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5.1&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=InternetNews+-+Python+Fans+Take+Aim+at+the+Enterprise&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F04%2F04%2Finternetnews-python-fans-take-aim-at-the-enterprise%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Sat, 05 Apr 2008 01:28:11 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: TurboGears Ultimate DVD now online, free at ShowMeDo</title>
	<guid>http://www.blueskyonmars.com/2008/04/04/turbogears-ultimate-dvd-now-online-free-at-showmedo/</guid>
	<link>http://www.blueskyonmars.com/2008/04/04/turbogears-ultimate-dvd-now-online-free-at-showmedo/</link>
	<description>&lt;p&gt;In June 2006, I shipped the &lt;a href=&quot;http://turbogears.org/ultimate.html&quot;&gt;TurboGears Ultimate DVD&lt;/a&gt;, featuring several hours of useful screencast material for TurboGears programmers. I produced the DVD with TurboGears 0.9a6 (or so) code, but much of what is talked about there applies to TurboGears 1.0x users. A big thanks to Ian Oszvald and Kyran Dale for putting the effort into getting 2GB of material transcoded and online: &lt;a href=&quot;http://showmedo.com/videos/series?name=IadG6S6pR&quot;&gt;TurboGears Ultimate DVD (TG v1.0) - video tutorials to learn turbogears, web_development, web_framework, python, javascript, web_application, cheeseshop, generic_function, JSON, metaclass, widget, API, sqlalchemy, cherrypy, sqlobject, WSGI&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5.1&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=TurboGears+Ultimate+DVD+now+online%2C+free+at+ShowMeDo&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F04%2F04%2Fturbogears-ultimate-dvd-now-online-free-at-showmedo%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Fri, 04 Apr 2008 16:06:26 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Robert Brewer: CherryPy 3 request_queue_size</title>
	<guid>http://www.aminus.org/blogs/xmlsrv/970@http://www.aminus.org/blogs/</guid>
	<link>http://www.aminus.org/blogs/index.php/2007/10/02/cherrypy_3_request_queue_size?blog=2</link>
	<description>&lt;p&gt;Well, that was instructive. Leaving &lt;code&gt;server.request_queue_size&lt;/code&gt; at the default 5:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;C:\Python24\Lib\site-packages&amp;gt;python cherrypy\test\benchmark.py
Starting CherryPy app server...
Started in 1.10800004005 seconds

Client Thread Report (1000 requests, 14 byte response body, 10 server threads):

threads | Completed | Failed | req/sec | msec/req | KB/sec |
     10 |      1000 |      0 |  736.81 |    1.357 | 119.36 |
     20 |      1000 |      0 |  436.07 |    2.293 |  70.64 |
     30 |      1000 |      0 |  348.38 |    2.870 |  56.44 |
     40 |      1000 |      0 |  233.10 |    4.290 |  37.76 |
     50 |      1000 |      0 |  296.77 |    3.370 |  48.08 |
Average |    1000.0 |    0.0 | 410.226 |    2.836 | 66.456 |

Client Thread Report (1000 requests, 14 bytes via staticdir, 10 server threads):

threads | Completed | Failed | req/sec | msec/req | KB/sec |
     10 |      1000 |      0 |  421.73 |    2.371 |  87.30 |
     20 |      1000 |      0 |  374.87 |    2.668 |  77.60 |
     30 |      1000 |      0 |  306.71 |    3.260 |  63.49 |
     40 |      1000 |      0 |  240.08 |    4.165 |  49.70 |
     50 |      1000 |      0 |  170.03 |    5.881 |  35.20 |
Average |    1000.0 |    0.0 | 302.684 |    3.669 | 62.658 |

Size Report (1000 requests, 50 client threads, 10 server threads):

    bytes | Completed | Failed | req/sec | msec/req |   KB/sec |
       10 |      1000 |      0 |  187.98 |    5.320 |    29.70 |
      100 |      1000 |      0 |  207.45 |    4.820 |    51.45 |
     1000 |      1000 |      0 |  186.89 |    5.351 |   210.81 |
    10000 |      1000 |      0 |  228.12 |    4.384 |  2262.07 |
   100000 |      1000 |      0 |  245.60 |    4.072 | 24022.01 |
100000000 |      1000 |     10 |   20.83 |   48.001 | 20358.12 |
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Upping &lt;code&gt;server.request_queue_size&lt;/code&gt; to 128:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;C:\Python24\Lib\site-packages&amp;gt;python cherrypy\test\benchmark.py
Starting CherryPy app server...
Started in 1.10700011253 seconds

Client Thread Report (1000 requests, 14 byte response body, 10 server threads):

threads | Completed | Failed | req/sec | msec/req |  KB/sec |
     10 |      1000 |      0 |  745.38 |    1.342 |  120.75 |
     20 |      1000 |      0 |  772.32 |    1.295 |  125.12 |
     30 |      1000 |      0 |  654.11 |    1.529 |  105.97 |
     40 |      1000 |      0 |  929.02 |    1.076 |  150.50 |
     50 |      1000 |      0 |  641.03 |    1.560 |  103.85 |
Average |    1000.0 |    0.0 | 748.372 |   1.3604 | 121.238 |

Client Thread Report (1000 requests, 14 bytes via staticdir, 10 server threads):

threads | Completed | Failed | req/sec | msec/req |  KB/sec |
     10 |      1000 |      0 |  547.89 |    1.825 |  113.41 |
     20 |      1000 |      0 |  588.10 |    1.700 |  121.74 |
     30 |      1000 |      0 |  704.42 |    1.420 |  145.82 |
     40 |      1000 |      0 |  547.89 |    1.825 |  113.41 |
     50 |      1000 |      0 |  516.96 |    1.934 |  107.01 |
Average |    1000.0 |    0.0 | 581.052 |   1.7408 | 120.278 |

Size Report (1000 requests, 50 client threads, 10 server threads):

    bytes | Completed | Failed | req/sec | msec/req |   KB/sec |
       10 |      1000 |      0 |  622.35 |    1.607 |    98.33 |
      100 |      1000 |      0 |  604.74 |    1.654 |   149.37 |
     1000 |      1000 |      0 |  667.74 |    1.498 |   752.54 |
    10000 |      1000 |      0 |  890.31 |    1.123 |  8837.25 |
   100000 |      1000 |      0 |  728.44 |    1.373 | 71247.09 |
100000000 |      1000 |    202 |   12.81 |   78.094 |     None |
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://www.aminus.org/blogs/index.php/2007/10/02/cherrypy_3_request_queue_size?blog=2&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
	<pubDate>Thu, 03 Apr 2008 05:00:16 +0000</pubDate>
	<dc:creator>fumanchu</dc:creator>
</item>
<item>
	<title>Robert Brewer: Please don't use wsgiapp</title>
	<guid>http://www.aminus.org/blogs/xmlsrv/956@http://www.aminus.org/blogs/</guid>
	<link>http://www.aminus.org/blogs/index.php/2007/07/24/please_don_t_use_wsgiapp?blog=2</link>
	<description>&lt;p&gt;Gordon Tillman has a &lt;a href=&quot;http://www.gordontillman.info/Development/DjangoCherryPy&quot;&gt;wiki page&lt;/a&gt; up on how to mix Django content into a CherryPy site. It's easy and probably works, but please don't do it anymore.&lt;/p&gt;

&lt;p&gt;We're officially going to deprecate the wsgiapp Tool because 1) it doesn't conform to the WSGI spec (and cannot be fixed to do so), and 2) there's a better way to mix content in a CherryPy site: &lt;code&gt;tree.graft&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;tree.graft(app, script_name)&lt;/code&gt; method is the proper way to add Django or other WSGI content to an existing CherryPy site. Instead of &lt;em&gt;nesting&lt;/em&gt; the two frameworks, we &lt;em&gt;branch&lt;/em&gt; instead. To take Gordon's example, instead of:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class DjangoApp(object):
    _cp_config = {
        'tools.wsgiapp.on': True,
        'tools.wsgiapp.app': AdminMediaHandler(WSGIHandler()),
}
...
cherrypy.tree.mount(DjangoApp(), '/')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should always write this instead:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cherrypy.tree.graft(AdminMediaHandler(WSGIHandler()), '/')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Look, if you nest the one inside the other, CherryPy's going to do an awful lot of HTTP request parsing that is going to be &lt;strong&gt;completely redundant&lt;/strong&gt;, since Django's going to do it again anyway. And this code is not very fast. Your site is going to crawl. That's strike one for nesting.&lt;/p&gt;

&lt;p&gt;Strike two is the &quot;always on&quot; nature of nesting as opposed to branching. When you write your request/response cycle &lt;a href=&quot;http://toys.jacobian.org/presentations/2007/oscon/tutorial/#s37&quot;&gt;like an onion&lt;/a&gt;, every component which could &lt;em&gt;possibly&lt;/em&gt; play a part in the request has to be called, even if just to reply &quot;I'm not involved in this one&quot;. Given the slowness of Python function calls, this is rarely a good thing. If you thought your site was crawling before... This was a major design flaw of CherryPy 2, and is a major reason CherryPy 3 is 3x faster: the old Filters were called all the time, even if you didn't need them; the new Tools are only called when they're applicable.&lt;/p&gt;

&lt;p&gt;Strike three against the nested approach is that it's always easier to traverse a tree of siblings than it is to traverse a nested set; programmers, for some reason, like to hide information from you, including how their site components go together. The branched version will be much easier to reason about, statically analyze, and write inspection tools for.&lt;/p&gt;

&lt;p&gt;So please, use &lt;code&gt;tree.graft&lt;/code&gt;, and stop using the wsgiapp Tool in CherryPy 3. We're going to &lt;a href=&quot;http://www.cherrypy.org/ticket/700&quot;&gt;formally deprecate&lt;/a&gt; it soon.&lt;/p&gt;
&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://www.aminus.org/blogs/index.php/2007/07/24/please_don_t_use_wsgiapp?blog=2&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
	<pubDate>Thu, 03 Apr 2008 05:00:16 +0000</pubDate>
	<dc:creator>fumanchu</dc:creator>
</item>
<item>
	<title>Robert Brewer: Lines of code</title>
	<guid>http://www.aminus.org/blogs/xmlsrv/953@http://www.aminus.org/blogs/</guid>
	<link>http://www.aminus.org/blogs/index.php/2007/07/09/lines_of_code?blog=2</link>
	<description>&lt;p&gt;I was asked last week how many lines of code some of my projects are, and didn't have an answer handy. Fortunately, it's easy to write a LOC counter in Python:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&quot;&quot;&quot;Calculate LOC (lines of code) for a given package directory.&quot;&quot;&quot;

import os
import re

def loc(path, pattern=&quot;^.*\.py$&quot;):
    &quot;&quot;&quot;Return the number of lines of code for all files in the given path.

    If the 'pattern' argument is provided, it must be a regular expression
    against which each filename will be matched. By default, all filenames
    ending in &quot;.py&quot; are analyzed.
    &quot;&quot;&quot;
    lines = 0
    for root, dirs, files in os.walk(path):
        for name in files:
            if re.match(pattern, name):
                f = open(os.path.join(root, name), 'rb')
                for line in f:
                    line = line.strip()
                    if line and not line.startswith(&quot;#&quot;):
                        lines += 1
                f.close()
    return lines
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I've added the above to my company's public-domain &lt;code&gt;misc&lt;/code&gt; package at &lt;a href=&quot;http://projects.amor.org/misc/&quot;&gt;http://projects.amor.org/misc/&lt;/a&gt;. Here are the results for my high-priority projects (some are proprietary):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; from misc import loc
&amp;gt;&amp;gt;&amp;gt; loc.loc(r&quot;C:\Python24\Lib\site-packages\raisersedge&quot;)
2290
&amp;gt;&amp;gt;&amp;gt; loc.loc(r&quot;C:\Python24\Lib\site-packages\dejavu&quot;)
7703
&amp;gt;&amp;gt;&amp;gt; loc.loc(r&quot;C:\Python24\Lib\site-packages\geniusql&quot;)
9509
&amp;gt;&amp;gt;&amp;gt; loc.loc(r&quot;C:\Python24\Lib\site-packages\cherrypy&quot;)
16391
&amp;gt;&amp;gt;&amp;gt; loc.loc(r&quot;C:\Python24\Lib\site-packages\endue&quot;)
9339
&amp;gt;&amp;gt;&amp;gt; loc.loc(r&quot;C:\Python24\Lib\site-packages\mcontrol&quot;)
11512
&amp;gt;&amp;gt;&amp;gt; loc.loc(r&quot;C:\Python24\Lib\site-packages\misc&quot;)
4648
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;~= 61 kloc. Pretty hefty for a single in-house web app stack. :/ But, hey, nobody said integration projects were easy.&lt;/p&gt;
&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://www.aminus.org/blogs/index.php/2007/07/09/lines_of_code?blog=2&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
	<pubDate>Thu, 03 Apr 2008 05:00:16 +0000</pubDate>
	<dc:creator>fumanchu</dc:creator>
</item>
<item>
	<title>Robert Brewer: Web Site Process Bus</title>
	<guid>http://www.aminus.org/blogs/xmlsrv/952@http://www.aminus.org/blogs/</guid>
	<link>http://www.aminus.org/blogs/index.php/2007/06/24/web_site_process_bus?blog=2</link>
	<description>&lt;p&gt;WSGI has enabled an ecosystem where site deployers can, in theory, mix multiple applications from various frameworks into a single web site, served by a single HTTP server. And that's great. But there are several areas where WSGI is purposefully silent, where there is still room for standards-based collaboration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;managing WSGI HTTP servers (start/stop/restart)&lt;/li&gt;
&lt;li&gt;construction of the WSGI component graph (servers -&gt; middlewares -&gt; apps)&lt;/li&gt;
&lt;li&gt;main process state control (start/stop/restart/graceful)&lt;/li&gt;
&lt;li&gt;site-wide services (autoreload, thread monitors, site logging)&lt;/li&gt;
&lt;li&gt;config file formats and parsing for all of the above&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most frameworks address all of the above already, to varying degrees; however, they still tend to do so in a very monolithic manner. Paste is notable for attempting to provide some of them in discrete pieces (especially WSGI graph construction and a config format tailor-made for it).&lt;/p&gt;

&lt;p&gt;But I'm going to focus here on just two of these issues: process state and site-wide services. I believe we can separate these two from the rest of the pack and provide a simple, common specification for both, one that's completely implementable in 100 lines of code by any framework.&lt;/p&gt;

&lt;h2&gt;The problem&lt;/h2&gt;

&lt;p&gt;One of the largest issues when combining multiple frameworks in a single process is answering the question, &quot;who's in control of the site as a whole?&quot; Multiple frameworks means multiple code bases who all think they should provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the startup script&lt;/li&gt;
&lt;li&gt;daemonization&lt;/li&gt;
&lt;li&gt;dropping privileges&lt;/li&gt;
&lt;li&gt;PID file management&lt;/li&gt;
&lt;li&gt;site logging&lt;/li&gt;
&lt;li&gt;autoreload&lt;/li&gt;
&lt;li&gt;signal handling&lt;/li&gt;
&lt;li&gt;sys.exit calls&lt;/li&gt;
&lt;li&gt;atexit handlers&lt;/li&gt;
&lt;li&gt;main thread error trapping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...and they often disagree about those behaviors. Throw Apache or lighttpd into the mix and you've got some serious deployment issues.&lt;/p&gt;

&lt;p&gt;The typical solution to this is to have each component provide a means of shutting off each process-controlling feature. For example, CherryPy 3 obeys the config entry &lt;code&gt;engine.autoreload_on = False&lt;/code&gt;, while &lt;code&gt;django-admin.py&lt;/code&gt; takes a &lt;code&gt;--noreload&lt;/code&gt; command-line arg. But these are different for each framework, and difficult to coordinate as the number of components grows. Since, for example, only one autoreloader is needed per site, a more usable solution would be to selectively turn &lt;em&gt;on&lt;/em&gt; just one instead of turning &lt;em&gt;off&lt;/em&gt; all but one.&lt;/p&gt;

&lt;p&gt;For a worse example, let's look at handling SIGTERM. Currently, we have the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://www.aminus.org/blogs/media/wspb-before.gif&quot; alt=&quot;SIGTERM before WSPBus&quot; /&gt;&lt;/p&gt;

&lt;p&gt;OK, Django doesn't actually provide a SIGTERM handler, but you get the idea. If several components register a SIGTERM handler, only one of them will &quot;win&quot; by virtue of being the last one to register. And chances are, the winning handler will shut down its component cleanly and then exit the process, leaving other components to fend for themselves.&lt;/p&gt;

&lt;p&gt;In fact, there's a whole list of negatives for the monolithic approach to process control and site services:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Frameworks and servers have to provide all desirable site behaviors, or force their packagers/deployers to develop them ad-hoc.&lt;/li&gt;
&lt;li&gt;Frameworks and servers all have different API's for changing process state. Race conditions and unpredictable outcomes are common.&lt;/li&gt;
&lt;li&gt;Frameworks and servers all have different API's for reacting to process state changes. Resource acquisition and cleanup becomes a huge unknown.&lt;/li&gt;
&lt;li&gt;Frameworks and servers have to know they're being deployed alongside other frameworks and servers.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We could attempt to solve this with a Grand Unified &lt;a href=&quot;http://en.wikipedia.org/wiki/Servlet_container&quot;&gt;Site Container&lt;/a&gt;, but that would most likely:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;force a single daemon implementation, thus eliminating innovation in process invocation,&lt;/li&gt;
&lt;li&gt;force a single configuration syntax, thus denying any market over declaration styles,&lt;/li&gt;
&lt;li&gt;force a static set of site services, limiting any improvements in process interaction,&lt;/li&gt;
&lt;li&gt;add an additional dependency to every framework,&lt;/li&gt;
&lt;li&gt;deny using HTTP servers like Apache and lighttpd in the same process (since they do their own process control), and&lt;/li&gt;
&lt;li&gt;be a dumping-ground for every other aspect of web development, from databases to templating.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;A solution: the Web Site Process Bus&lt;/h2&gt;

&lt;p&gt;The Web Site Process Bus uses a simple publish/subscribe architecture to loosely connect WSGI components with site services. Here's our SIGTERM example, implemented with a WSPBus:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://www.aminus.org/blogs/media/wspb-after.gif&quot; alt=&quot;SIGTERM after WSPBus&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The singleton Bus object does three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It models server-availability state via a &quot;state&quot; attribute, which is a sentinel value from the set: (STARTING, STARTED, STOPPING, STOPPED).&lt;/li&gt;
&lt;li&gt;It possesses methods to change the state, such as &quot;start&quot;, &quot;stop&quot;, &quot;restart&quot;, &quot;graceful&quot;, and &quot;exit&quot;.&lt;/li&gt;
&lt;li&gt;It possesses &quot;publish&quot; and &quot;subscribe&quot;/&quot;unsubscribe&quot; methods for named channels.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each method which changes the state also has an equivalent named channel. Any framework, server, or other component may register code as a listener on any channel. For example, a web framework can register database-connection code to be run when the &quot;start&quot; method is called, and disconnection code for the &quot;stop&quot; method:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;bus.subscribe(&quot;start&quot;, orm.connpool.start)
bus.subscribe(&quot;stop&quot;, orm.connpool.stop)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Any channel which has no listeners will simply ignore all published messages. This allows component code to be much simpler; callers do not need to know whether their actions are appropriate--they are appropriate if a listener is subscribed to that channel.&lt;/p&gt;

&lt;p&gt;In addition to the builtin state-transition channels, components are free to define their own pub/sub channels. CherryPy's current implementation, for example, defines the additional channels &lt;code&gt;start_thread&lt;/code&gt; and &lt;code&gt;stop_thread&lt;/code&gt;, and registers channels for signals, such as &quot;SIGTERM&quot;, &quot;SIGHUP&quot;, and &quot;SIGUSR1&quot; (which then typically call bus methods like &quot;restart&quot; and &quot;exit&quot;). Some of these could be standardized. Other custom channels would be more naturally tightly-coupled, requiring awareness on the part of callers and callees.&lt;/p&gt;

&lt;p&gt;Since WSPB state-changing method calls are expected to be sporadic, and often fundamentally serial (e.g., &quot;autoreload&quot;), their execution is synchronous. Subscribers (mostly of custom channels), however, are free to return immediately, and continue their operation asynchronously.&lt;/p&gt;

&lt;h2&gt;Benefits&lt;/h2&gt;

&lt;p&gt;The WSPB cleanly solves all of the problems outlined above. The various components are no longer in competition over process state; instead, there is a single race-free state machine. However, no single component has to know whether or how many other components are deployed in the same site.&lt;/p&gt;

&lt;p&gt;Frameworks and servers can provide a subset of all site services, with a common, imperative-Python API for deployers to add or substitute their own. However, the WSPB doesn't define a config syntax, so each framework can continue to provide its own unique layer to translate config into that API. A deployer of a combined Pylons/Zope website could choose a Pylons startup script and config syntax to manage the lifecycle of the Zope components.&lt;/p&gt;

&lt;p&gt;The WSPB doesn't try to instantiate or compose WSGI components (server -&gt; middleware -&gt; app) either. So there's even room for site daemons which provide no traditional web app functionality; instead, they specialize in providing tools to compose WSGI component graphs via a config file or even a GUI.&lt;/p&gt;

&lt;p&gt;It also &quot;plays nice&quot; with &lt;code&gt;mod_python&lt;/code&gt;, &lt;code&gt;mod_proxy&lt;/code&gt;, &lt;code&gt;mod_wsgi&lt;/code&gt;, FastCGI, and SCGI. Those who develop WSGI gateways for these will have a clear incentive to consolidate their ad-hoc startup and shutdown models into the WSPB. For example, a modpython gateway can use apache.register_cleanup to just call bus.stop() instead of providing custom cleanup-declaration code.&lt;/p&gt;

&lt;p&gt;Best of all, the WSPB can be defined as a specification which any framework can provide in a small amount of code. Rather than attempt to draft the specification here (that can be hashed out on Web-SIG, since this is by no means complete), I'm just going to provide an example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;try:
    set
except NameError:
    from sets import Set as set
import sys
import threading
import time
import traceback as _traceback


# Use a flag to indicate the state of the bus.
class _StateEnum(object):
    class State(object):
        pass
states = _StateEnum()
states.STOPPED = states.State()
states.STARTING = states.State()
states.STARTED = states.State()
states.STOPPING = states.State()


class Bus(object):
    &quot;&quot;&quot;Process state-machine and messenger for HTTP site deployment.&quot;&quot;&quot;

    states = states
    state = states.STOPPED

    def __init__(self):
        self.state = states.STOPPED
        self.listeners = dict([(channel, set()) for channel
                               in ('start', 'stop', 'exit',
                                   'restart', 'graceful', 'log')])
        self._priorities = {}

    def subscribe(self, channel, callback, priority=None):
        &quot;&quot;&quot;Add the given callback at the given channel (if not present).&quot;&quot;&quot;
        if channel not in self.listeners:
            self.listeners[channel] = set()
        self.listeners[channel].add(callback)

        if priority is None:
            priority = getattr(callback, 'priority', 50)
        self._priorities[(channel, callback)] = priority

    def unsubscribe(self, channel, callback):
        &quot;&quot;&quot;Discard the given callback (if present).&quot;&quot;&quot;
        listeners = self.listeners.get(channel)
        if listeners and callback in listeners:
            listeners.discard(callback)
            del self._priorities[(channel, callback)]

    def publish(self, channel, *args, **kwargs):
        &quot;&quot;&quot;Return output of all subscribers for the given channel.&quot;&quot;&quot;
        if channel not in self.listeners:
            return []

        exc = None
        output = []

        items = [(self._priorities[(channel, listener)], listener)
                 for listener in self.listeners[channel]]
        items.sort()
        for priority, listener in items:
            # All listeners for a given channel are guaranteed to run even
            # if others at the same channel fail. We will still log the
            # failure, but proceed on to the next listener. The only way
            # to stop all processing from one of these listeners is to
            # raise SystemExit and stop the whole server.
            try:
                output.append(listener(*args, **kwargs))
            except (KeyboardInterrupt, SystemExit):
                raise
            except:
                self.log(&quot;Error in %r listener %r&quot; % (channel, listener),
                         traceback=True)
                exc = sys.exc_info()[1]
        if exc:
            raise
        return output

    def start(self):
        &quot;&quot;&quot;Start all services.&quot;&quot;&quot;
        self.state = states.STARTING
        self.log('Bus starting')
        self.publish('start')
        self.state = states.STARTED

    def restart(self):
        &quot;&quot;&quot;Restart the process (may close connections).&quot;&quot;&quot;
        self.stop()

        self.log('Bus restart')
        self.publish('restart')

    def graceful(self):
        &quot;&quot;&quot;Advise all services to reload.&quot;&quot;&quot;
        self.log('Bus graceful')
        self.publish('graceful')

    def block(self, state=states.STOPPED, interval=0.1):
        &quot;&quot;&quot;Wait for the given state, KeyboardInterrupt or SystemExit.&quot;&quot;&quot;
        try:
            while self.state != state:
                time.sleep(interval)
        except (KeyboardInterrupt, IOError):
            # The time.sleep call might raise
            # &quot;IOError: [Errno 4] Interrupted function call&quot; on KBInt.
            self.log('Keyboard Interrupt: shutting down bus')
            self.stop()
        except SystemExit:
            self.log('SystemExit raised: shutting down bus')
            self.stop()
            raise

    def stop(self):
        &quot;&quot;&quot;Stop all services.&quot;&quot;&quot;
        self.state = states.STOPPING
        self.log('Bus stopping')
        self.publish('stop')
        self.state = states.STOPPED

    def exit(self, status=0):
        &quot;&quot;&quot;Stop all services and exit the process.&quot;&quot;&quot;
        self.stop()

        self.log('Bus exit')
        self.publish('exit')
        sys.exit(status)

    def log(self, msg=&quot;&quot;, traceback=False):
        if traceback:
            exc = sys.exc_info()
            msg += &quot;\n&quot; + &quot;&quot;.join(_traceback.format_exception(*exc))
        self.publish('log', msg)
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://www.aminus.org/blogs/index.php/2007/06/24/web_site_process_bus?blog=2&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
	<pubDate>Thu, 03 Apr 2008 05:00:16 +0000</pubDate>
	<dc:creator>fumanchu</dc:creator>
</item>
<item>
	<title>Robert Brewer: It's official: CherryPy rocks</title>
	<guid>http://www.aminus.org/blogs/xmlsrv/948@http://www.aminus.org/blogs/</guid>
	<link>http://www.aminus.org/blogs/index.php/2007/03/16/it_s_official_cherrypy_rocks?blog=2</link>
	<description>&lt;p&gt;From &lt;a href=&quot;http://www.sucks-rocks.com/rate/ruby+on+rails/turbogears/django/cherrypy&quot;&gt;sucks-rocks.com&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://www.aminus.org/blogs/media/cprocks.png&quot; width=&quot;487&quot; height=&quot;134&quot; alt=&quot;CherryPy rocks&quot; /&gt;&lt;/p&gt;

&lt;p&gt;No, really. It rocks. Rocks, rocks, rocks.&lt;/p&gt;

&lt;p&gt;(Thanks, jamwt!)&lt;/p&gt;
&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://www.aminus.org/blogs/index.php/2007/03/16/it_s_official_cherrypy_rocks?blog=2&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
	<pubDate>Thu, 03 Apr 2008 05:00:16 +0000</pubDate>
	<dc:creator>fumanchu</dc:creator>
</item>
<item>
	<title>Robert Brewer: PyCon 2007 and CherryPy</title>
	<guid>http://www.aminus.org/blogs/xmlsrv/946@http://www.aminus.org/blogs/</guid>
	<link>http://www.aminus.org/blogs/index.php/2007/02/25/pycon_2007_and_cherrypy?blog=2</link>
	<description>&lt;p&gt;PyCon 2007 is nearing a close; here are some notes on how it affected CherryPy:&lt;/p&gt;

&lt;h2&gt;Web application deployment&lt;/h2&gt;

&lt;p&gt;Chad Whitacre (author of &lt;a href=&quot;http://www.zetadev.com/software/aspen/&quot;&gt;Aspen&lt;/a&gt;) herded several cats into a room on Sunday and forced us to discuss the various issues surrounding Python web application deployment. This is hinted at in the &lt;a href=&quot;http://www.python.org/dev/peps/pep-0333/&quot;&gt;WSGI spec&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Finally, it should be mentioned that the current version of WSGI does not prescribe any particular mechanism for &quot;deploying&quot; an application for use with a web server or server gateway. At the present time, this is necessarily implementation-defined by the server or gateway. After a sufficient number of servers and frameworks have implemented WSGI to provide field experience with varying deployment requirements, it may make sense to create another PEP, describing a deployment standard for WSGI servers and application frameworks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There were three basic realms where the participants agreed we could try to collaborate/standardize:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Process control: stop, start, restart, daemonization, signal handling, socket re-use, drop privileges, etc. If you're familiar with CherryPy 3, you'll recognize this list as 95% of the current cherrypy.engine object. The CherryPy team has already been discussing ways of breaking up the Engine object; this may facilitate that (and vice-versa). Joseph Tate volunteered to look at socket re-use issues specifically, but the general consensus seemed to be that much of this would be hashed out on Web-SIG.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;WSGI stack composition: Jim Fulton proposed that we could all agree on Paste Deploy (at least a good portion of the API) to manage this in a cross-framework manner. Most heads nodded, &quot;yes&quot;. Jim also proposed that each of the framework authors take the next week to refamiliarize themselves with Deploy, and then start pestering Ian Bicking with specific API issues. Ian suggested that he should fork Paste Deploy into another project specifically for this. For CherryPy, this would first mean offering standard egg entry points. [Personally, I'd like to standardize on a pure-Python API for deploy, not a config file format API. In other words, make the config file format optional, so that users of CP-only apps could avoid having to learn a distinct config file format for deployment. It should be possible to transform various config file formats into the same Python object(s).]&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Benchmarks: Jim also suggested we create a standard WSGI HTTP server benchmark suite, with various test applications and concurrency scenarios. This would compare various WSGI HTTP servers, as opposed to CherryPy's existing benchmark suite which compares successive versions of the full CP stack. Ian volunteered to begin work on that project (with the expectation that others would contribute substantial use cases, etc).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Others who were present for at least a portion of the long discussion: me, Mark Ramm, Kevin Dangoor, Ben Bangert, Jonathan Ellis, Matt Good, Brian Beck, and Calvin Hendryx-Parker.&lt;/p&gt;

&lt;h2&gt;WSGI middleware authoring&lt;/h2&gt;

&lt;p&gt;After some discussion with Mark (and he with Ian and Ben), we agreed that CherryPy could do more in the WSGI-middleware-authoring department. There is a continuous pressure to simply re-use or fix up the existing CherryPy request object to fill this need; however, there are some fundamental problems with that approach (such as the use of threadlocals to manage context, and the difficulty of streaming WSGI output &lt;em&gt;through&lt;/em&gt; a CherryPy app). At the moment, I'm leaning toward adding a new API to CherryPy which would be &lt;em&gt;similar&lt;/em&gt; to the application API, but specifically targeted at middleware authoring.&lt;/p&gt;
&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://www.aminus.org/blogs/index.php/2007/02/25/pycon_2007_and_cherrypy?blog=2&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
	<pubDate>Thu, 03 Apr 2008 05:00:16 +0000</pubDate>
	<dc:creator>admin</dc:creator>
</item>
<item>
	<title>Robert Brewer: help(CherryPy 3.0)</title>
	<guid>http://www.aminus.org/blogs/xmlsrv/938@http://www.aminus.org/blogs/</guid>
	<link>http://www.aminus.org/blogs/index.php/2007/01/20/help_cherrypy_3_0?blog=2</link>
	<description>&lt;h2&gt;Abstract&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;CherryPy just grew its first metaclass.&lt;/li&gt;
&lt;li&gt;CherryPy just grew its first stdlib monkeypatch.&lt;/li&gt;
&lt;li&gt;Because of 1 and 2, CherryPy is now a heck of a lot easier to learn and use.&lt;/li&gt;
&lt;li&gt;Points 1, 2, and 3 all apply to unreleased trunk code and are subject to change.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Intro&lt;/h2&gt;

&lt;p&gt;I've been a proper fool (and might still be). I've been telling everyone that CherryPy 3 is much easier to learn and use because it's been tailored to be help()-ful. What I meant was that you could open an interactive interpreter, type &lt;code&gt;help(cherrypy.&amp;lt;thing&amp;gt;)&lt;/code&gt; and have at least some idea of what it does. I spent quite a bit of time honing the top-level namespace down to as few components as possible (and some of the component namespaces, too) in order to make &lt;code&gt;help()&lt;/code&gt; easier to read.&lt;/p&gt;

&lt;p&gt;This is harder to do than you might think. Unlike simple linear scripts or libraries, the most important objects when CherryPy is &quot;live&quot; don't exist at an interactive prompt. The Request, Response, and Session objects are all heavily dependent on the context of a real HTTP conversation. They're hard to create in a vacuum. And although there's one of each per thread while the system is running, they are implemented as thread local objects so that the CherryPy programmer can treat each of them as if there were only one: a global.&lt;/p&gt;

&lt;h2&gt;Reusing thread locals&lt;/h2&gt;

&lt;p&gt;Thread locals are a great invention, but they suffer from one serious drawback when used in a threaded framework: they allow anyone to add attributes to them. If the framework re-uses the same thread for multiple requests, it becomes difficult to reliably clean out all of those attributes between requests.&lt;/p&gt;

&lt;p&gt;CherryPy's solution to that was to add a container in 2.1; instead of a separate thread local for the Request, Response, and Session objects, there is a single, hidden thread local called &lt;code&gt;cherrypy._serving&lt;/code&gt;, and the Request, Response, and Session objects for each thread are attributes of the &quot;serving&quot; object. This makes it easy for cleanup code: it just calls &lt;code&gt;cherrypy._serving.__dict__.clear()&lt;/code&gt; when the request ends. (Aside: this technique also allows the Request, Response and Session types to be overridden).&lt;/p&gt;

&lt;p&gt;However, pushing those objects into a container means they're no longer so easy to reference. CherryPy code would become uglier and more difficult if, instead of:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cherrypy.request.method
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;...you had to write:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cherrypy._serving.request.method
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So a &lt;code&gt;_ThreadLocalProxy&lt;/code&gt; class was introduced to allow CherryPy code to keep writing the nicer, shorter syntax. In short, it passes &lt;code&gt;__getattr__&lt;/code&gt; (and other double-underscore methods) through to a wrapped object. So &lt;code&gt;cherrypy.request&lt;/code&gt; became a proxy object to a wrapped Request object. Ditto for response and session.&lt;/p&gt;

&lt;p&gt;That was fine for CherryPy 2, but one of the goals for version 3.0 is better IDE support. Most IDE's at least provide calltips for code completion, but there aren't usually any HTTP requests coming in as you're writing code! CP 2's thread local proxies didn't have a request object in the main thread (or any thread that wasn't started by the HTTP server), so typing &lt;code&gt;cherrypy.request.&lt;/code&gt; couldn't result in a calltip as you coded. The solution for CherryPy 3 was to have the proxy's &lt;code&gt;__getattr__&lt;/code&gt; and friends wrap a default object if a live object could not be found. And the default objects' attributes are true defaults; if they're not overridden (in config or code), they won't change when the system goes live. This makes interactive exploration even easier; you can forget all about the threading and pretend you're looking at live, global objects.&lt;/p&gt;

&lt;h2&gt;help(proxy) isn't helpful&lt;/h2&gt;

&lt;p&gt;But there's another catch: one of the few problems with using a proxy object in pure Python is that it's no longer of the same type as the wrapped object. Unfortunately for us, Python's builtin &lt;code&gt;help&lt;/code&gt; function uses pydoc, and pydoc calls &lt;code&gt;type(obj)&lt;/code&gt; quite a bit.&lt;/p&gt;

&lt;p&gt;You can certainly call &lt;code&gt;help(cherrypy.request.run)&lt;/code&gt; and get the correct docstring, because &quot;run&quot; is an attribute of &lt;code&gt;cherrypy.request&lt;/code&gt;, the proxy calls &lt;code&gt;__getattr__&lt;/code&gt; first, and then &lt;code&gt;type()&lt;/code&gt; is called on the attribute, not the request object/proxy. But if you attempt &lt;code&gt;help(cherrypy.request)&lt;/code&gt;, you're in for some confusion, because the proxy implementation leaks out.&lt;/p&gt;

&lt;p&gt;Or rather, it did leak out until just now. I took the plunge and CherryPy now monkeypatches pydoc, so that it &quot;passes the &lt;code&gt;help()&lt;/code&gt; call through the proxy&quot;. Monkeypatching the standard library is of course a huge no-no, but the alternative was to essentially copy and paste most of pydoc and distribute the result with CherryPy. Now, &lt;code&gt;help(cherrypy.response)&lt;/code&gt; at least prints:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; help(cherrypy.response)
Help on Response in module cherrypy._cprequest object:

class Response(__builtin__.object)
 |  An HTTP Response, including status, headers, and body.
 |  
 |  Application developers should use Response.headers (a dict) to
 |  set or modify HTTP response headers. When the response is finalized,
 |  Response.headers is transformed into Response.header_list as
 |  (key, value) tuples.
 |  
 |  Methods defined here:
 |  
 |  __init__(self)
 |  
 |  check_timeout(self)
 |      If now &amp;gt; self.time + self.timeout, set self.timed_out.
 |      
 |      This purposefully sets a flag, rather than raising an error,
 |      so that a monitor thread can interrupt the Response thread.
 |  
 |  collapse_body(self)
 |  
 |  finalize(self)
 |      Transform headers (and cookies) into self.header_list.
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __dict__ = &amp;lt;dictproxy object&amp;gt;
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__ = &amp;lt;attribute '__weakref__' of 'Response' objects&amp;gt;
 |      list of weak references to the object (if defined)
 |  
 |  body = &amp;lt;cherrypy._cprequest.Body object&amp;gt;
 |      The body of the HTTP response (the response entity).
 |  
 |  cookie = &amp;lt;SimpleCookie: &amp;gt;
 |  
 |  header_list = []
 |  
 |  headers = {}
 |  
 |  status = ''
 |  
 |  stream = False
 |  
 |  time = None
 |  
 |  timed_out = False
 |  
 |  timeout = 300
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Documenting data&lt;/h2&gt;

&lt;p&gt;But there's a further flaw with the above output of &lt;code&gt;help()&lt;/code&gt;; none of the data members of the Response class are documented! A few of them are mentioned in the class docstring, to be sure, but hardly to a truly useful extent. The Request object is an even poorer state, since it has so many more data members.&lt;/p&gt;

&lt;p&gt;The solution for &lt;em&gt;that&lt;/em&gt; issue is somewhat complicated, as well. It turns out that there are plenty of good documentation &lt;em&gt;generators&lt;/em&gt; for Python code (that emit HTML or text; epydoc and pudge spring to mind), but no serious helpers for making &lt;code&gt;help()&lt;/code&gt; more informative. This is a real shame; I would almost always rather have &lt;code&gt;help()&lt;/code&gt; be truly helpful than go read a book or search online docs.&lt;/p&gt;

&lt;p&gt;So I proposed a (small!) metaclass to help alleviate the problem for CherryPy. When you look at CherryPy source code, now, you might see something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Request(object):
    &quot;&quot;&quot;An HTTP request.&quot;&quot;&quot;

    __metaclass__ = cherrypy._AttributeDocstrings

    prev = None
    prev__doc = &quot;&quot;&quot;
    The previous Request object (if any). This should be None
    unless we are processing an InternalRedirect.&quot;&quot;&quot;

    # Conversation/connection attributes
    local = http.Host(&quot;localhost&quot;, 80)
    local__doc = \
        &quot;An http.Host(ip, port, hostname) object for the server socket.&quot;

    remote = http.Host(&quot;localhost&quot;, 1111)
    remote__doc = \
        &quot;An http.Host(ip, port, hostname) object for the client socket.&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;_AttributeDocstrings&lt;/code&gt; metaclass does one thing: finds class members whose names look like &lt;code&gt;&amp;lt;attrname&amp;gt;__doc&lt;/code&gt;, takes their &lt;code&gt;str&lt;/code&gt; value, formats it, and folds it into the class docstring. Here's a snippet of the resulting &lt;code&gt;help()&lt;/code&gt; output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Help on Request in module cherrypy._cprequest object:

class Request(__builtin__.object)
 |  An HTTP request.
 |  
 |  local [= http.Host('localhost', 80, 'localhost')]:
 |      An http.Host(ip, port, hostname) object for the server socket.
 |  
 |  prev [= None]:
 |      The previous Request object (if any). This should be None
 |      unless we are processing an InternalRedirect.
 |  
 |  remote [= http.Host('localhost', 1111, 'localhost')]:
 |      An http.Host(ip, port, hostname) object for the client socket.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Christian's first question was, &quot;why not just write it yourself by hand in the docstring?&quot; Here's the long answer. The metaclass:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Places the docstring nearer to the attribute declaration.&lt;/li&gt;
&lt;li&gt;Makes attribute docs more uniform (&quot;name (default): doc&quot;).&lt;/li&gt;
&lt;li&gt;Automatically gets the attribute name right in the docstring.&lt;/li&gt;
&lt;li&gt;Automatically gets the default value right in the docstring.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I chose the naming convention because it allows the attribute name and the &lt;code&gt;attribute__doc&lt;/code&gt; name to line up horizontally (it doesn't matter which comes first; I prefer to put the doc after the attribute). It also looks similar to the conventions in Python's C code, where doc variable names look like &lt;code&gt;module_attribute__doc__&lt;/code&gt; or sometimes just &lt;code&gt;attribute_doc&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Code faster&lt;/h2&gt;

&lt;p&gt;Hopefully these two improvements, although more awkward than I like implementation-wise, will make &lt;em&gt;using&lt;/em&gt; CherryPy much easier and faster. Feel free to &lt;code&gt;help()&lt;/code&gt; us out by writing a few data member docstrings!&lt;/p&gt;
&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://www.aminus.org/blogs/index.php/2007/01/20/help_cherrypy_3_0?blog=2&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
	<pubDate>Thu, 03 Apr 2008 05:00:16 +0000</pubDate>
	<dc:creator>fumanchu</dc:creator>
</item>
<item>
	<title>Robert Brewer: CherryPy 3 has fastest WSGI server yet</title>
	<guid>http://www.aminus.org/blogs/xmlsrv/933@http://www.aminus.org/blogs/</guid>
	<link>http://www.aminus.org/blogs/index.php/2006/12/23/cherrypy_3_has_fastest_wsgi_server_yet?blog=2</link>
	<description>&lt;p&gt;A couple of months ago, in response to &lt;a href=&quot;http://william-os4y.livejournal.com/2420.html&quot;&gt;someone else's speed claims&lt;/a&gt;, I posted a comment that CherryPy's built in WSGI server could serve 1200 simple requests per second. The demo used Apache's &quot;ab&quot; tool to test (&quot;-k -n 3000 -c %s&quot;). In the last few days before the release of CherryPy 3.0 final, I've done some further optimization of cherrypy.wsgiserver, and now get 2000+ req/sec on my modest laptop.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;threads | Completed | Failed | req/sec | msec/req | KB/sec |
     10 |      3000 |      0 | 2170.79 |    0.461 | 358.18 |
     20 |      3000 |      0 | 2080.34 |    0.481 | 343.26 |
     30 |      3000 |      0 | 1920.31 |    0.521 | 316.85 |
     40 |      3000 |      0 | 2051.84 |    0.487 | 338.55 |
     50 |      3000 |      0 | 2051.84 |    0.487 | 338.55 |
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The improvements are due to a variety of optimizations, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replacing mimetools/rfc822.Message with custom code for reading headers.&lt;/li&gt;
&lt;li&gt;Using socket.sendall instead of a socket fileobject for writes.&lt;/li&gt;
&lt;li&gt;Generic hand-tuning of code loops.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I want to make it clear that the benchmark does not exercise any part of CherryPy other than the WSGI server. I used a very simple WSGI application (not the full CherryPy stack):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def simple_app(environ, start_response):
    &quot;&quot;&quot;Simplest possible application object&quot;&quot;&quot;
    status = '200 OK'
    response_headers = [('Content-type','text/plain'),
                        ('Content-Length','19')]
    start_response(status, response_headers)
    return ['My Own Hello World!']
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The full stack of CherryPy includes the WSGI application side as well, and consequently takes more time. But that has risen from about 380 requests per second in October to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Client Thread Report (1000 requests, 14 byte response body, 10 server threads):

threads | Completed | Failed | req/sec | msec/req | KB/sec |
     10 |      1000 |      0 |  536.86 |    1.863 |  85.36 |
     20 |      1000 |      0 |  509.47 |    1.963 |  81.01 |
     30 |      1000 |      0 |  499.28 |    2.003 |  79.39 |
     40 |      1000 |      0 |  491.90 |    2.033 |  78.21 |
     50 |      1000 |      0 |  504.32 |    1.983 |  80.19 |
Average |    1000.0 |    0.0 | 508.366 |    1.969 | 80.832 |
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want to benchmark the full CherryPy stack on your own, just install &lt;a href=&quot;http://www.cherrypy.org&quot;&gt;CherryPy&lt;/a&gt; and run the script at &lt;code&gt;cherrypy/test/benchmark.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's the other script for the &quot;bare server&quot; benchmarks:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import re
import sys
import threading
import time
from cherrypy import _cpmodpy

AB_PATH = &quot;&quot;
APACHE_PATH = &quot;apache&quot;
SCRIPT_NAME = &quot;&quot;
PORT = 8080


class ABSession:
    &quot;&quot;&quot;A session of 'ab', the Apache HTTP server  benchmarking tool.&quot;&quot;&quot;
    parse_patterns = [('complete_requests', 'Completed',
                       r'^Complete requests:\s*(\d+)'),
                      ('failed_requests', 'Failed',
                       r'^Failed requests:\s*(\d+)'),
                      ('requests_per_second', 'req/sec',
                       r'^Requests per second:\s*([0-9.]+)'),
                      ('time_per_request_concurrent', 'msec/req',
                       r'^Time per request:\s*([0-9.]+).*concurrent requests\)$'),
                      ('transfer_rate', 'KB/sec',
                       r'^Transfer rate:\s*([0-9.]+)'),
                      ]

    def __init__(self, path=SCRIPT_NAME + &quot;/&quot;, requests=3000, concurrency=10):
        self.path = path
        self.requests = requests
        self.concurrency = concurrency

    def args(self):
        assert self.concurrency &amp;gt; 0
        assert self.requests &amp;gt; 0
        return (&quot;-k -n %s -c %s &amp;lt;a href=&quot;http://localhost:%s%s&quot;&quot;&amp;gt;http://localhost:%s%s&quot;&amp;lt;/a&amp;gt; %
                (self.requests, self.concurrency, PORT, self.path))

    def run(self):
        # Parse output of ab, setting attributes on self
        args = self.args()
        self.output = _cpmodpy.read_process(AB_PATH or &quot;ab&quot;, args)
        for attr, name, pattern in self.parse_patterns:
            val = re.search(pattern, self.output, re.MULTILINE)
            if val:
                val = val.group(1)
                setattr(self, attr, val)
            else:
                setattr(self, attr, None)


safe_threads = (25, 50, 100, 200, 400)
if sys.platform in (&quot;win32&quot;,):
    # For some reason, ab crashes with &amp;gt; 50 threads on my Win2k laptop.
    safe_threads = (10, 20, 30, 40, 50)


def thread_report(path=SCRIPT_NAME + &quot;/&quot;, concurrency=safe_threads):
    sess = ABSession(path)
    attrs, names, patterns = zip(*sess.parse_patterns)
    rows = [('threads',) + names]
    for c in concurrency:
        sess.concurrency = c
        sess.run()
        rows.append([c] + [getattr(sess, attr) for attr in attrs])
    return rows

def print_report(rows):
    widths = []
    for i in range(len(rows[0])):
        lengths = [len(str(row[i])) for row in rows]
        widths.append(max(lengths))
    for row in rows:
        print
        for i, val in enumerate(row):
            print str(val).rjust(widths[i]), &quot;|&quot;,
    print


if __name__ == '__main__':

    def simple_app(environ, start_response):
        &quot;&quot;&quot;Simplest possible application object&quot;&quot;&quot;
        status = '200 OK'
        response_headers = [('Content-type','text/plain'),
                            ('Content-Length','19')]
        start_response(status, response_headers)
        return ['My Own Hello World!']

    from cherrypy import wsgiserver as w
    s = w.CherryPyWSGIServer((&quot;localhost&quot;, PORT), simple_app)
    threading.Thread(target=s.start).start()
    try:
        time.sleep(1)
        print_report(thread_report())
    finally:
        s.stop()
&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://www.aminus.org/blogs/index.php/2006/12/23/cherrypy_3_has_fastest_wsgi_server_yet?blog=2&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://b2evolution.net/&quot;&gt;b2evolution&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
	<pubDate>Thu, 03 Apr 2008 05:00:16 +0000</pubDate>
	<dc:creator>fumanchu</dc:creator>
</item>
<item>
	<title>Christian Wyglendowski: Reading Chunked HTTP/1.1 Responses</title>
	<guid>http://blog.dowski.com/2008/04/02/reading-chunked-http11-responses/</guid>
	<link>http://blog.dowski.com/2008/04/02/reading-chunked-http11-responses/</link>
	<description>&lt;p&gt;For work today I wanted a way to iterate over an HTTP response with chunked transfer-coding on a chunk-for-chunk basis.  I didn&amp;#8217;t see a builtin way to do that with &lt;code&gt;httplib&lt;/code&gt;.  It supports chunked reads but you have to specify the amount that you want to read if you don&amp;#8217;t want it to buffer.  I just wanted it to read and yield each chunk that it received from the server.&lt;/p&gt;
&lt;p&gt;For my first crack at it I really just tried to use the &lt;code&gt;httplib&lt;/code&gt; basics:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;import&lt;/span&gt; &lt;span&gt;httplib&lt;/span&gt;
&amp;nbsp;
conn = &lt;span&gt;httplib&lt;/span&gt;.&lt;span&gt;HTTPConnection&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'localhost:8080'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
conn.&lt;span&gt;request&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'GET'&lt;/span&gt;, &lt;span&gt;'/'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
r = conn.&lt;span&gt;getresponse&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
data = r.&lt;span&gt;read&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
&lt;span&gt;while&lt;/span&gt; data:
    &lt;span&gt;print&lt;/span&gt; data
    data = r.&lt;span&gt;read&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That worked but since I won&amp;#8217;t know the chunk size in real-life, I would probably get output similar to this:&lt;/p&gt;
&lt;pre&gt;
Chunk 0
Ch
unk 1
Chun
k 2
Chunk
3
Chunk 4
...
&lt;/pre&gt;
&lt;p&gt;I really wanted that chunk-for-chunk iteration.  After taking a look at the very readable &lt;code&gt;httplib&lt;/code&gt; source this evening, it wasn&amp;#8217;t very hard to accomplish.  I basically just took the &lt;code&gt;httplib.HTTPResponse._read_chunked&lt;/code&gt; method and modified it to be a generator.  I subclassed &lt;code&gt;HTTPResponse&lt;/code&gt; and stuck my generator in an &lt;code&gt;__iter__&lt;/code&gt; method.  Behold; now you can do this sort of thing:&lt;/p&gt;

&lt;div class=&quot;wp_syntax&quot;&gt;&lt;div class=&quot;code&quot;&gt;&lt;pre class=&quot;python&quot;&gt;&lt;span&gt;if&lt;/span&gt; __name__ == &lt;span&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;:
    &lt;span&gt;import&lt;/span&gt; &lt;span&gt;httplib&lt;/span&gt;
    &lt;span&gt;import&lt;/span&gt; iresponse
    conn = &lt;span&gt;httplib&lt;/span&gt;.&lt;span&gt;HTTPConnection&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'localhost:8080'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    conn.&lt;span&gt;response_class&lt;/span&gt; = iresponse.&lt;span&gt;IterableResponse&lt;/span&gt;
    conn.&lt;span&gt;request&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;'GET'&lt;/span&gt;, &lt;span&gt;'/'&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    r = conn.&lt;span&gt;getresponse&lt;/span&gt;&lt;span&gt;&amp;#40;&lt;/span&gt;&lt;span&gt;&amp;#41;&lt;/span&gt;
    &lt;span&gt;for&lt;/span&gt; &lt;span&gt;chunk&lt;/span&gt; &lt;span&gt;in&lt;/span&gt; r:
        &lt;span&gt;print&lt;/span&gt; &lt;span&gt;chunk&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With nice results like this:&lt;/p&gt;
&lt;pre&gt;
Chunk 0
Chunk 1
Chunk 2
Chunk 3
Chunk 4
...
&lt;/pre&gt;
&lt;p&gt;You can download &lt;a href=&quot;http://projects.dowski.com/view/iresponse&quot;&gt;the iresponse module&lt;/a&gt; from my projects site.  There is also a small CherryPy application that serves some data with chunked transfer-coding in case any of you want to fiddle with it.&lt;/p&gt;
&lt;p&gt;cw&lt;/p&gt;</description>
	<pubDate>Wed, 02 Apr 2008 04:35:28 +0000</pubDate>
	<dc:creator>christian</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: MichiPUG meeting on Thursday, April 3</title>
	<guid>http://www.blueskyonmars.com/2008/04/01/michipug-meeting-on-thursday-april-3/</guid>
	<link>http://www.blueskyonmars.com/2008/04/01/michipug-meeting-on-thursday-april-3/</link>
	<description>&lt;p&gt;The Michigan Python Users Group (&lt;a href=&quot;http://groups.google.com/group/michipug/web/index-2&quot;&gt;MichiPUG&lt;/a&gt;) monthly meeting is coming up on Thursday, April 3.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ve got two exciting topics for this month&amp;#8217;s meeting. The first part is &lt;a href=&quot;http://compoundthinking.com/blog/&quot;&gt;Mark Ramm&lt;/a&gt; leading some discussion on documentation tools (including &lt;a href=&quot;http://sphinx.pocoo.org/&quot;&gt;Sphinx&lt;/a&gt;). I roped Mark into this because I haven&amp;#8217;t yet run Sphinx, but it looks great. He&amp;#8217;ll also talk about &lt;a href=&quot;http://zedshaw.com/projects/idiopidae/index.html&quot;&gt;Idiopidae&lt;/a&gt; which &lt;a href=&quot;http://zedshaw.com/blog/index.html&quot;&gt;Zed Shaw&lt;/a&gt; and Mark were hacking on at PyCon.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll also lead some discussion and experimentation with &lt;a href=&quot;http://www.fiber-space.de/EasyExtend/doc/EE.html&quot;&gt;EasyExtend&lt;/a&gt;, Kay Schluehr&amp;#8217;s tool for monkeying with Python&amp;#8217;s syntax.&lt;/p&gt;
&lt;p&gt;Should be a fun time, and I hope to see you &lt;a href=&quot;http://groups.google.com/group/michipug/web/SRT%20Solutions&quot;&gt;there&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5.1&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=MichiPUG+meeting+on+Thursday%2C+April+3&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F04%2F01%2Fmichipug-meeting-on-thursday-april-3%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 01 Apr 2008 16:23:51 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Psychotic: optimizing Python compiler</title>
	<guid>http://www.blueskyonmars.com/2008/04/01/psychotic-optimizing-python-compiler/</guid>
	<link>http://www.blueskyonmars.com/2008/04/01/psychotic-optimizing-python-compiler/</link>
	<description>&lt;p&gt;An idea that I had at PyCon has finally come to fruition: introducing &lt;a href=&quot;http://psychotic.googlecode.com/&quot;&gt;Psychotic&lt;/a&gt;, a pure Python optimizing compiler that achieves some pretty impressive results.&lt;/p&gt;
&lt;p&gt;For a new project, Psychotic has a good deal of documentation. There&amp;#8217;s also the &lt;a href=&quot;http://dangoor.blip.tv/file/787194/&quot;&gt;introductory screencas&lt;/a&gt;t, which is &amp;#8220;lightning talk sized&amp;#8221; (under 5 minutes).&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s actually a &lt;a href=&quot;http://www.sitepen.com/blog/2008/04/01/project-announcement-psychotic-optimizing-python-compiler/&quot;&gt;fuller announcement&lt;/a&gt; over at the SitePen blog.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5.1&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=Psychotic%3A+optimizing+Python+compiler&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F04%2F01%2Fpsychotic-optimizing-python-compiler%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 01 Apr 2008 11:08:50 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Rich UI Webapps with TurboGears 2 and Dojo Screencast</title>
	<guid>http://www.blueskyonmars.com/2008/03/31/rich-ui-webapps-with-turbogears-2-and-dojo-screencast/</guid>
	<link>http://www.blueskyonmars.com/2008/03/31/rich-ui-webapps-with-turbogears-2-and-dojo-screencast/</link>
	<description>&lt;p&gt;I have recorded a screencast of my PyCon 2008 talk and put the code for the demo app online. Check it out on the &lt;a href=&quot;http://www.sitepen.com/blog/2008/03/31/rich-ui-webapps-with-turbogears-2-and-dojo-screencast/&quot;&gt;SitePen Blog  » Rich UI Webapps with TurboGears 2 and Dojo Screencast&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sharethis.com/item?&amp;wp=2.5&amp;amp;publisher=4c75e961-1ece-4620-a912-84dd6eb72e2f&amp;amp;title=Rich+UI+Webapps+with+TurboGears+2+and+Dojo+Screencast&amp;amp;url=http%3A%2F%2Fwww.blueskyonmars.com%2F2008%2F03%2F31%2Frich-ui-webapps-with-turbogears-2-and-dojo-screencast%2F&quot;&gt;ShareThis&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Mon, 31 Mar 2008 17:23:08 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: My PyCon 2008 report</title>
	<guid>http://www.blueskyonmars.com/2008/03/21/my-pycon-2008-report/</guid>
	<link>http://www.blueskyonmars.com/2008/03/21/my-pycon-2008-report/</link>
	<description>&lt;p&gt;Some initial thoughts on PyCon 2008 are now up &lt;a href=&quot;http://www.sitepen.com/blog/2008/03/20/pycon-2008-report/&quot;&gt;on the SitePen blog&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&quot;akst_link&quot;&gt;&lt;a href=&quot;http://www.blueskyonmars.com/?p=2298&amp;amp;akst_action=share-this&quot; title=&quot;E-mail this, post to del.icio.us, etc.&quot; id=&quot;akst_link_2298&quot; class=&quot;akst_share_link&quot; rel=&quot;nofollow&quot;&gt;Share This&lt;/a&gt;
&lt;/p&gt;</description>
	<pubDate>Sat, 22 Mar 2008 03:28:24 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: TurboGears looking for Google SoC Students!</title>
	<guid>http://www.blueskyonmars.com/2008/03/20/turbogears-looking-for-google-soc-students/</guid>
	<link>http://www.blueskyonmars.com/2008/03/20/turbogears-looking-for-google-soc-students/</link>
	<description>&lt;p&gt;TurboGears has been accepted as a &lt;a href=&quot;http://code.google.com/soc/2008/turbogears/about.html&quot;&gt;Google Summer of Code organization&lt;/a&gt;. Chris Arndt has put together a page at docs.turbogears.org to pull together all of the &lt;a href=&quot;http://docs.turbogears.org/GSoC&quot;&gt;TG Summer of Code information&lt;/a&gt;. Congrats to Chris and the others for pulling together this year&amp;#8217;s Summer of Code effort for TG!&lt;/p&gt;
&lt;p&gt;Next week is signup time for students (March 24-31), so if you&amp;#8217;re interested in getting paid to work on TurboGears this summer, check out the &lt;a href=&quot;http://docs.turbogears.org/GSoC&quot;&gt;TG SoC info page&lt;/a&gt;.&lt;/p&gt;
&lt;p class=&quot;akst_link&quot;&gt;&lt;a href=&quot;http://www.blueskyonmars.com/?p=2293&amp;amp;akst_action=share-this&quot; title=&quot;E-mail this, post to del.icio.us, etc.&quot; id=&quot;akst_link_2293&quot; class=&quot;akst_share_link&quot; rel=&quot;nofollow&quot;&gt;Share This&lt;/a&gt;
&lt;/p&gt;</description>
	<pubDate>Thu, 20 Mar 2008 11:19:01 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: MichiPUG meeting: Nose by Jason Pellerin</title>
	<guid>http://www.blueskyonmars.com/2008/03/02/michipug-meeting-nose-by-jason-pellerin/</guid>
	<link>http://www.blueskyonmars.com/2008/03/02/michipug-meeting-nose-by-jason-pellerin/</link>
	<description>&lt;p&gt;Jason Pellerin is going to be giving a talk about his &lt;a href=&quot;http://somethingaboutorange.com/mrl/projects/nose/&quot;&gt;Nose&lt;/a&gt; testing tool at the Michigan Python Users Group (MichiPUG). I&amp;#8217;ve been a Nose users since the very beginning, so I&amp;#8217;m happy that Jason himself is giving a talk on it.&lt;/p&gt;
&lt;p&gt;As usual, the meeting is on the first Thursday of the month (March 6th, in this case) at 7PM. Meetings are always free.&lt;/p&gt;
&lt;p&gt;And, as has been the case the past several months, &lt;a href=&quot;http://srtsolutions.com/&quot;&gt;SRT Solutions&lt;/a&gt; is going to be hosting the meeting at their perfect downtown Ann Arbor location. In addition to &lt;a href=&quot;http://groups.google.com/group/michipug/web/SRT%20Solutions&quot;&gt;the instructions on how to get to SRT&lt;/a&gt;, I&amp;#8217;ll also mention that street parking is free after 6PM and usually readily available a couple blocks north at Ann and Fifth (right next to the City Hall/Police Station building).&lt;/p&gt;
&lt;p&gt;Unfortunately, I most likely won&amp;#8217;t see you there for this month&amp;#8217;s meeting, as it&amp;#8217;s kindergarten roundup time for Ann Arbor Schools and we&amp;#8217;re trying to figure out the best kindergarten choice for our daughter. Hopefully, I will be seeing some of you at PyCon in a couple of weeks!&lt;/p&gt;
&lt;p class=&quot;akst_link&quot;&gt;&lt;a href=&quot;http://www.blueskyonmars.com/?p=2271&amp;amp;akst_action=share-this&quot; title=&quot;E-mail this, post to del.icio.us, etc.&quot; id=&quot;akst_link_2271&quot; class=&quot;akst_share_link&quot; rel=&quot;nofollow&quot;&gt;Share This&lt;/a&gt;
&lt;/p&gt;</description>
	<pubDate>Mon, 03 Mar 2008 02:40:22 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: Cobra programming language</title>
	<guid>http://www.blueskyonmars.com/2008/02/08/cobra-programming-language/</guid>
	<link>http://www.blueskyonmars.com/2008/02/08/cobra-programming-language/</link>
	<description>&lt;p&gt;So, we&amp;#8217;ve got &lt;a href=&quot;http://jython.org/Project/index.html&quot;&gt;Jython&lt;/a&gt; and &lt;a href=&quot;http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython&quot;&gt;IronPython&lt;/a&gt; as &lt;a href=&quot;http://python.org/&quot;&gt;Python&lt;/a&gt; language reimplementations. There&amp;#8217;s also &lt;a href=&quot;http://boo.codehaus.org/&quot;&gt;Boo&lt;/a&gt;, which is clearly heavily inspired by Python but has some interesting extensions (static typing, for example). I just came across &lt;a href=&quot;http://cobra-language.com/&quot;&gt;Cobra&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cobra, like Boo, is built on the &lt;a href=&quot;http://www.mono-project.com/Main_Page&quot;&gt;.NET platform&lt;/a&gt;. The syntax is clearly inspired by Python, which I consider a good thing. In keeping line noise to a minimum, Cobra even ditches the &amp;#8220;:&amp;#8221; at the end of the line preceding a block of code. Chuck Esterbrook has also pulled inspiration from a number of other places. I recognize some &lt;a href=&quot;http://www.digitalmars.com/d/&quot;&gt;D&lt;/a&gt; and &lt;a href=&quot;http://www.eiffel.com/&quot;&gt;Eiffel&lt;/a&gt; in there (it&amp;#8217;s got design by contract and unit tests built right into the classes). There&amp;#8217;s a comparison to Python available right on the Cobra site.&lt;/p&gt;
&lt;p&gt;Something that&amp;#8217;s interesting about Cobra is that it&amp;#8217;s self-hosting. Even though C# has been getting more powerful over time, I&amp;#8217;m sure that Cobra can move forward more quickly with its even more succinct syntax.&lt;/p&gt;
&lt;p&gt;As a Python guy, though, I can&amp;#8217;t help but notice things that seem to be missing (or are possibly just missing from the docs).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Functions as first class objects. All of the examples are inside of classes, which just seems silly. I also haven&amp;#8217;t seen the syntax for passing a function around (can you even do that?) This is a powerful feature.&lt;/li&gt;
&lt;li&gt;Metaclasses don&amp;#8217;t seem to exist in Cobra. You don&amp;#8217;t need them all the time, but you can make some APIs a lot nicer if you use them when appropriate.&lt;/li&gt;
&lt;li&gt;Function parameter declaration is weaker. Function parameter capabilities seem to be the same as in any other .NET language. It allows you to have variable arguments, but that&amp;#8217;s about as fancy as you can get.&lt;/li&gt;
&lt;li&gt;Objects are not extensible. You can&amp;#8217;t just go and hang random attributes off of an object, and there are actually some times when this is convenient to do.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I do think it&amp;#8217;s interesting to see more languages popping up that offer both static and dynamic typing. I&amp;#8217;ll be curious to see how that plays out over time.&lt;/p&gt;
&lt;p class=&quot;akst_link&quot;&gt;&lt;a href=&quot;http://www.blueskyonmars.com/?p=2251&amp;amp;akst_action=share-this&quot; title=&quot;E-mail this, post to del.icio.us, etc.&quot; id=&quot;akst_link_2251&quot; class=&quot;akst_share_link&quot; rel=&quot;nofollow&quot;&gt;Share This&lt;/a&gt;
&lt;/p&gt;</description>
	<pubDate>Fri, 08 Feb 2008 17:18:35 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Kevin Dangoor: When something goes missing, you realize how much you use it</title>
	<guid>http://www.blueskyonmars.com/2008/01/18/when-something-goes-missing-you-realize-how-much-you-use-it/</guid>
	<link>http://www.blueskyonmars.com/2008/01/18/when-something-goes-missing-you-realize-how-much-you-use-it/</link>
	<description>&lt;p&gt;Like, say, the Python Cheeseshop. I&amp;#8217;ve been using Python eggs extensively since mid-2005 and have grown used to how easy it is to easy_install &amp;#8220;random package&amp;#8221;. Lately, I&amp;#8217;ve been using zc.buildout to get entire environments set up, and it&amp;#8217;s Cheeseshop dependent in the same way that easy_install is.&lt;/p&gt;
&lt;p&gt;Thanks to everyone who&amp;#8217;s been involved with coding and running the Cheeseshop. It&amp;#8217;s a great resource!&lt;/p&gt;
&lt;p&gt;Now can we have it back, please? &lt;img src=&quot;http://www.blueskyonmars.com/wp-includes/images/smilies/icon_smile.gif&quot; alt=&quot;:)&quot; class=&quot;wp-smiley&quot; /&gt; &lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;Error...

There's been a problem with your request

psycopg.OperationalError: no connection to the server
&lt;/code&gt;
&lt;/pre&gt;
&lt;p class=&quot;akst_link&quot;&gt;&lt;a href=&quot;http://www.blueskyonmars.com/?p=2217&amp;amp;akst_action=share-this&quot; title=&quot;E-mail this, post to del.icio.us, etc.&quot; id=&quot;akst_link_2217&quot; class=&quot;akst_share_link&quot; rel=&quot;nofollow&quot;&gt;Share This&lt;/a&gt;
&lt;/p&gt;</description>
	<pubDate>Fri, 18 Jan 2008 15:25:15 +0000</pubDate>
	<dc:creator>Kevin Dangoor</dc:creator>
</item>
<item>
	<title>Uche and Chimezie Ogbuji: del.icio.us bookmarks for 2008-01-15</title>
	<guid>http://copia.ogbuji.net/blog/2008-01-16/del.icio.us.links</guid>
	<link>http://copia.ogbuji.net/blog/2008-01-16/del.icio.us.links</link>
	<description>&lt;p&gt;&lt;!--keywords: del.icio.us,xml,visualization,rules,science,tool,ebook,illustration,book,radio,editor,online,browser,species,logic --&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&quot;&lt;a href=&quot;http://www.nearfield.org/2007/12/fictional-radio-spaces&quot;&gt;Fictional radio-spaces&lt;/a&gt;&quot;: &amp;quot;Using inspiration from richly illustrated books on botany, zoology and natural history, Ingeborg arrived at the concept of an encyclopeadia of radio waves that contains a selection of fictional radio ‘species’&amp;quot; &lt;em&gt;(from chimezie)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&quot;&lt;a href=&quot;http://www.aaaipress.org/Classic/Buchanan/buchanan.html&quot;&gt;Rule-Based Expert Systems: The MYCIN Experiments of the Stanford Heuristic Programming Project&lt;/a&gt;&quot;: &amp;quot;In this book we share the results of many experiments performed in that time ... The book is intended to be a critical analysis of several pieces of related research, performed by a large number of scientists. We believe that the whole field of AI will b &lt;em&gt;(from chimezie)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&quot;&lt;a href=&quot;http://xopus.com/product/how/&quot;&gt;How does it work?&lt;/a&gt;&quot;: &amp;quot;When Xopus starts, it creates a new stylesheet based on the stylesheet you 