<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-8212254010436871241</atom:id><lastBuildDate>Thu, 15 Dec 2011 11:37:38 +0000</lastBuildDate><category>xenophobia</category><category>off-topic</category><category>zope</category><category>loophole</category><title>Mock It!</title><description>News from the testing underground</description><link>http://mockit.blogspot.com/</link><managingEditor>noreply@blogger.com (malthe)</managingEditor><generator>Blogger</generator><openSearch:totalResults>62</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/MockIt" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="mockit" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-938583489990137633</guid><pubDate>Thu, 22 Sep 2011 13:33:00 +0000</pubDate><atom:updated>2011-09-23T07:07:02.834+02:00</atom:updated><title>Python, long words and the soft hyphen</title><description>The HTML specification (any of them) does not require or allow a user agent to manage text hyphenation. Instead, it must rely on hints provided by the document:&lt;br /&gt;
&lt;blockquote&gt;
&lt;i&gt;The soft hyphen tells the user agent where a line break can occur.&lt;/i&gt;&lt;/blockquote&gt;
In English, (very) long words are relatively infrequent, and as such, hyphenation is not particularly important. The lack of good hyphenation rarely breaks a page layout.&lt;br /&gt;
&lt;br /&gt;
In German – and in Germanic languages in general – words are long! If you have a page layout with narrow columns (a left-hand side navigation for instance), lines might extend further than you'd like them to.&lt;br /&gt;
&lt;br /&gt;
The following Python function inserts &lt;i&gt;soft hyphens&lt;/i&gt; into a text string, guided by a hyphenation dictionary:&lt;br /&gt;
&lt;br /&gt;
&lt;script src="https://gist.github.com/1234726.js"&gt;
 
&lt;/script&gt;
If you can't see the script embedded above, you can see the &lt;a href="https://gist.github.com/1234726"&gt;source&lt;/a&gt; here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-938583489990137633?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2011/09/python-long-words-and-soft-hyphen.html</link><author>noreply@blogger.com (malthe)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-27591962645731826</guid><pubDate>Thu, 22 Sep 2011 09:05:00 +0000</pubDate><atom:updated>2011-09-23T07:08:20.229+02:00</atom:updated><title>"Less.app" on linux</title><description>From the homepage:

&lt;br /&gt;
&lt;blockquote&gt;
&lt;i&gt;LESS extends CSS with dynamic behavior such as variables, mixins, operations and functions. LESS runs on both the client-side (IE 6+, Webkit, Firefox) and server-side, with Node.js.
&lt;/i&gt;&lt;/blockquote&gt;
In a production environment – unless you have special reasons not to – it's probably best to "cook" your stylesheets on the server-side. It saves browser resources and allows your site to be shown without Javascript enabled.&lt;br /&gt;
&lt;br /&gt;
On the Mac, there's &lt;a href="http://incident57.com/less/"&gt;Less.app&lt;/a&gt;. The homepage looks a bit like a release announcement from Apple. What it does is to monitor a configurable set of directories for changes and invokes the "less" compiler.&lt;br /&gt;
&lt;br /&gt;
On Linux, the equivalent is a few lines of bash:
&lt;script src="https://gist.github.com/1234308.js"&gt;
 
&lt;/script&gt;
Note that you must have &lt;a href="http://lesscss.org/#-server-side-usage"&gt;less.js&lt;/a&gt; (via node.js) and&amp;nbsp;&lt;a href="http://github.com/rvoicilas/inotify-tools"&gt;inotify-tools&lt;/a&gt; installed.&lt;br /&gt;
&lt;br /&gt;
If you can't see the script embedded above, you can see the &lt;a href="https://gist.github.com/1234308"&gt;source&lt;/a&gt; here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-27591962645731826?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2011/09/lessapp-on-linux.html</link><author>noreply@blogger.com (malthe)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-2042783168270684185</guid><pubDate>Thu, 14 Jul 2011 07:16:00 +0000</pubDate><atom:updated>2011-07-15T08:20:40.776+02:00</atom:updated><title>Speed up your Plone 4 site with Chameleon</title><description>The &lt;a href="http://pagetemplates.org/"&gt;fast template engine&lt;/a&gt; that runs on just about any Python platform version 2.5 and up now runs on Plone 4!&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's already running live in production on Enfold's &lt;a href="http://ploud.net/"&gt;Ploud&lt;/a&gt; infrastructure where they see a consistent 20% or higher increase in performance.&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To get Chameleon running on your site, simply add a dependency on &lt;a href="http://pypi.python.org/pypi/five.pt"&gt;five.pt&lt;/a&gt; and make sure you get version 2.1. Plone's automatic package configuration does the rest.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: monospace; font-size: 13px; white-space: pre; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt; &lt;span class="Apple-style-span" style="font-family: monospace; font-size: 13px; white-space: pre; "&gt;  eggs = &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: monospace; font-size: 13px; white-space: pre; "&gt;    ... &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: monospace; font-size: 13px; white-space: pre; "&gt;    five.pt&amp;gt;=2.1&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Support for Zope 2 security and restricted Python is included.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's not just about speed.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Other good reasons to use Chameleon are:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Easier debugging – cuts out most of the noise from stack traces&lt;/li&gt;&lt;li&gt;Less dependencies – uses only the standard Python library&lt;/li&gt;&lt;li&gt;Flexible parser – supports non-compliant markup and SGML&lt;/li&gt;&lt;li&gt;Works with any framework on almost all Python platforms&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Please report any issues on the &lt;a href="https://github.com/malthe/chameleon/issues"&gt;bug tracker&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-2042783168270684185?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2011/07/speed-up-your-plone-4-site-with.html</link><author>noreply@blogger.com (malthe)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-8500838725546107103</guid><pubDate>Wed, 02 Mar 2011 10:34:00 +0000</pubDate><atom:updated>2011-03-02T12:10:53.605+01:00</atom:updated><title>Writing a single-source library for Python 2 and 3</title><description>The &lt;a href="http://pypi.python.org/pypi/Chameleon"&gt;recently released&lt;/a&gt; Chameleon template compiler was written as a &lt;i&gt;single source&lt;/i&gt; for all Python platforms &gt; 2.5, including Python 3.x (and PyPy).&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;I'd like to share my experience in taking this approach instead of using the &lt;a href="http://docs.python.org/library/2to3.html"&gt;2to3&lt;/a&gt; tool or a similar technique (read &lt;a href="http://lucumr.pocoo.org/2011/1/22/forwards-compatible-python/"&gt;this article&lt;/a&gt; by Armin Ronacher to compare).&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I started out requiring Python 2.7. This is actually my recommendation if you're contemplating writing a cross-platform compatible library. This release of Python 2 supports most of the features of Python 3 and has syntax-compatibility. And most applications that run on 2.5 will also run without modification on 2.7.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;However, in my case, Python 2.5 was a priority. It's somewhat tedious to support this version because the exception handler syntax is incompatible with Python 3. You have to call &lt;tt&gt;sys.exc_info()&lt;/tt&gt; to get the exception instance in every handler. To remedy this, you can try and minimize the use of exception handlers; most of the standard library code offer interfaces that don't raise exceptions. The unit test module is also somewhat outdated and I ended up with a dependency on &lt;a href="http://pypi.python.org/pypi/unittest2"&gt;unittest2&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's hard to avoid conditional imports and use of various aliases such as:&lt;/div&gt;&lt;div&gt;&lt;pre&gt;  try:         fast_string = str         str = unicode         bytes = fast_string     except NameError:         long = int         basestring = str         fast_string = str&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;Most libraries won't have to care about string encoding to the point where this is  necessary, but in the case of a template engine, this stuff matters.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In terms of packaging, I decided to require &lt;a href="http://pypi.python.org/pypi/distribute"&gt;distribute&lt;/a&gt;. I don't know what the support for Python 3 is with &lt;a href="http://pypi.python.org/pypi/setuptools"&gt;setuptools&lt;/a&gt;, but my attempts to make it work failed miserably. After adding trove classifiers for all supported versions, my package showed up in the Python 3 &lt;a href="http://pypi.python.org/pypi?:action=browse&amp;amp;c=533&amp;amp;show=all"&gt;compatibility list&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why not use the conversion tool? Truth is that I didn't care to try this approach because it seemed error prone and complex. I'd rather "dumb down" my library code than have to automatically translated. With any sort of code generation there's going to be questions such as "where is the generated code?" and "how to step-debug it?". With the single source approach, everything's business as usual. There's always a downside in supporting old Python releases in that you can't use all the new standard library code. But the conversion tool can't help there.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-8500838725546107103?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2011/03/writing-single-source-library-for.html</link><author>noreply@blogger.com (malthe)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-6437142970488745236</guid><pubDate>Tue, 22 Feb 2011 12:53:00 +0000</pubDate><atom:updated>2011-03-02T11:34:27.176+01:00</atom:updated><title>Chameleon on Python 2, 3 and PyPy</title><description>&lt;div&gt;This is to announce that a new installment of the &lt;a href="http://chameleon.repoze.org/"&gt;Chameleon&lt;/a&gt; template compiler is available. A single codebase targets an all-new set of platforms: 2.5+, 3.1+ and PyPy! Currently it includes an engine for the &lt;a href="http://docs.zope.org/zope2/zope2book/AppendixC.html"&gt;Zope Page Templates&lt;/a&gt; language. There are no hard library dependencies.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To try it out, install it from PyPi:&lt;/div&gt;&lt;div&gt;&lt;pre&gt;  # easy_install Chameleon&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;Or get a copy from the repository:&lt;/div&gt;&lt;pre&gt;  http://github.com/malthe/chameleon&lt;/pre&gt;&lt;div&gt;You can report bugs on the &lt;a href="http://github.com/malthe/chameleon/issues"&gt;issue tracker&lt;/a&gt;. Chameleon is the default template engine for the &lt;a href="http://docs.pylonsproject.org/projects/pyramid/1.0/narr/templates.html#chameleon-zpt-templates"&gt;Pyramid&lt;/a&gt; web framework, but can be used on just about any system that uses Python. There's also support for Zope and Plone via add-on packages.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-6437142970488745236?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2011/02/chameleon-on-python-27-31-and-pypy.html</link><author>noreply@blogger.com (malthe)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-8041386920412859144</guid><pubDate>Thu, 27 Jan 2011 12:20:00 +0000</pubDate><atom:updated>2011-01-27T13:29:05.189+01:00</atom:updated><title>HTTP response proxy with Zope 2</title><description>&lt;div&gt;You sometimes want to proxy an HTTP object through your site.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If &lt;tt&gt;response&lt;/tt&gt; is your &lt;tt&gt;urllib2&lt;/tt&gt; response object, then for Zope 2 to actually accept it as a proper downstream response, you need to apply this little trick:&lt;/div&gt;&lt;div&gt;&lt;pre&gt;  from zope.interface import alsoProvides&lt;br /&gt;  from ZPublisher.Iterators import IStreamIterator&lt;br /&gt;  alsoProvides(response, IStreamIterator)&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;Without the interface idiosyncrasy, Zope might have just checked for a &lt;tt&gt;read&lt;/tt&gt; method on the response object and be done with it.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-8041386920412859144?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2011/01/http-response-proxy-with-zope-2.html</link><author>noreply@blogger.com (malthe)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-4925997945404472865</guid><pubDate>Sun, 12 Dec 2010 16:38:00 +0000</pubDate><atom:updated>2010-12-12T17:52:54.376+01:00</atom:updated><title>Getting registry settings in Plone to display in fieldsets</title><description>Although still a little &lt;a href="http://mockit.blogspot.com/2010/12/rich-text-on-property-sheet.html"&gt;rough around the edges&lt;/a&gt; with regards to supporting less trivial fields such as rich text, Plone's new settings registry framework works really well. It basically lets you point to a Zope schema interface and have the contained fields presented as a control panel form.&lt;br /&gt;&lt;br /&gt;I recently wanted to code up a control panel form modelled as a series of fieldsets (displayed with a tabbed interface in Plone). Each of the fieldsets corresponded in my case to its own interface declaration, but potentially I wanted to allow for any sort of nesting.&lt;br /&gt;&lt;br /&gt;This proved to be somewhat out of the ordinary for &lt;a href="http://pypi.python.org/pypi/plone.registry"&gt;plone.registry&lt;/a&gt;. It includes a &lt;i&gt;records proxy&lt;/i&gt; class which neatly does the mapping between the interface and the registry. The following gist includes two points of interest in particular: an &lt;i&gt;abstract&lt;/i&gt; records proxy class that takes care of this mapping for any type of schema and it also demonstrates the syntax for rendering your interfaces in different form groups – which will ultimately display as form tabs.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  &lt;a href="http://gist.github.com/738156"&gt;http://gist.github.com/738156&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There currently seems to be the issue that error messages that appear inside a tab aren't immediately visible when you post back the form. The user will for the moment have to interpret the generic error message as "please look under each tab to find the concrete error".&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-4925997945404472865?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2010/12/getting-registry-settings-in-plone-to.html</link><author>noreply@blogger.com (malthe)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-1880815500217281005</guid><pubDate>Thu, 02 Dec 2010 09:48:00 +0000</pubDate><atom:updated>2010-12-02T10:54:49.533+01:00</atom:updated><title>Rich text on a property sheet</title><description>It's the Zope CMF property-sheet-counterpart to "snakes on a plane". Here's how to do it:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  &lt;a href="https://gist.github.com/725048"&gt;https://gist.github.com/725048&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why would anyone go through all that?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had a brief e-mail chat with Martin Aspeli where it was established fairly well that certain control panel-like properties go well with the new registry for Plone and others don't go well at all, namely those that are more complex than numbers and strings. &lt;i&gt;Rich text values&lt;/i&gt; are such complex properties.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The very same limitations apply for the venerable CMF property sheets. But on the other hand, you've got to put this stuff somewhere and hiding it away in some obscure annotation isn't exactly transparent.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So in a paean to the legacy software that the CMF is, I ended up storing the rich text value in said manner and it isn't all that awful.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-1880815500217281005?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2010/12/rich-text-on-property-sheet.html</link><author>noreply@blogger.com (malthe)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-7788966959907864080</guid><pubDate>Sun, 21 Nov 2010 17:44:00 +0000</pubDate><atom:updated>2010-11-21T19:15:03.715+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">xenophobia</category><category domain="http://www.blogger.com/atom/ns#">loophole</category><category domain="http://www.blogger.com/atom/ns#">off-topic</category><title>Off-topic: On xenophobia or why we're looking for an apartment in Malmö</title><description>&lt;div&gt;There's a tide of &lt;a href="http://www.opendemocracy.net/democracy-europe_constitution/fear_3590.jsp"&gt;repressive immigration policies&lt;/a&gt; passing through Europe, in particular in Denmark. Very long story cut short, it's difficult and (very) expensive to get to live with your spouse who is a foreign national (outside of the EU). Moreover, it takes many years to get a permanent and secure status. However, there's a loop-hole which circumvents my government's (numerous) attempts to keep out foreign spouses and all it requires is a 10-week stay in another EU-country. After that, you can literally waltz right back into your own country.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have therefore decided to move to Sweden with my (pregnant!) fiancé for a while and thus ask for help in finding a place to stay, preferably in &lt;a href="http://maps.google.com/maps?q=map+of+Malm%C3%B6&amp;amp;um=1&amp;amp;ie=UTF-8&amp;amp;hq=&amp;amp;hnear=Malm%C3%B6+Municipality,+Sweden&amp;amp;ei=AmDpTNLGDoSXOojFhOsM&amp;amp;sa=X&amp;amp;oi=geocode_result&amp;amp;ct=title&amp;amp;resnum=1&amp;amp;ved=0CBYQ8gEwAA"&gt;Malmö&lt;/a&gt;. We'd like to move as soon as possible!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Any help is greatly appreciated.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-7788966959907864080?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2010/11/off-topic-on-xenophobia-or-why-were.html</link><author>noreply@blogger.com (malthe)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-6174906992182057268</guid><pubDate>Thu, 18 Nov 2010 12:20:00 +0000</pubDate><atom:updated>2010-11-18T13:24:34.885+01:00</atom:updated><title>Getting broken objects out of ZODB</title><description>Here's a small script that can help you get (broken object) data out of a ZODB database for which you don't have the right software: &lt;a href="https://gist.github.com/704910"&gt;https://gist.github.com/704910&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As a minimum, you need to know which persistent base class the original object was based on, i.e. persistent object, mapping, list, dict etc. If you're on a Plone site, you'll probably want to use an Archetypes base class.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The technique can be used to migrate an old site to a completely new software platform without bothering to try and install the original software which may be so outdated that even the Python syntax is wrong. Or simply to get your data out of the site.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-6174906992182057268?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2010/11/getting-broken-objects-out-of-zodb.html</link><author>noreply@blogger.com (malthe)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-5760020033893027784</guid><pubDate>Tue, 09 Nov 2010 12:00:00 +0000</pubDate><atom:updated>2010-11-09T15:03:06.581+01:00</atom:updated><title>Translation and Punctuation</title><description>The Plone CMS includes &lt;span style="font-style: italic;"&gt;gettext&lt;/span&gt; translations for a great many languages. For some reason, most translations differ in its punctuation in comparison to the original text - typically the translation is missing a punctuation character. This makes translated text look bad in general, but may also have some side-effects such as duplicate status messages being shown because one includes punctuation while the other does not.&lt;br /&gt;&lt;br /&gt;Armed with a &lt;a href="https://gist.github.com/669027"&gt;script&lt;/a&gt; written for the occasion and a checkout of all Plone translations for both current major versions, I have made an effort to make punctuations uniform such that the punctuation used in the original text is reflected in the translation. Excluded from processing is translation files which contain Chinese punctuation (i.e. "。" and "：").&lt;br /&gt;&lt;br /&gt;Please visit the changesets for &lt;a href="http://dev.plone.org/collective/changeset/226325/PloneTranslations/branches/3.x"&gt;3.x&lt;/a&gt; and &lt;a href="http://dev.plone.org/collective/changeset/226326/PloneTranslations/trunk"&gt;4.x&lt;/a&gt; for reference. While I have tried my best to ensure that the processing was correct, it's worthwhile for translators to review - or revert!&lt;br /&gt;&lt;br /&gt;You can use this script for your gettext-based translations. I use the following command-line:&lt;br /&gt;&lt;pre&gt;  find . -name "*.po" -exec fix-po.py '{}' \;&lt;br /&gt;&lt;/pre&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-5760020033893027784?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2010/11/translation-and-punctuation.html</link><author>noreply@blogger.com (malthe)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-4199623562418631224</guid><pubDate>Thu, 04 Nov 2010 14:49:00 +0000</pubDate><atom:updated>2010-11-04T15:56:38.104+01:00</atom:updated><title>On-the-fly image scales with Archetypes</title><description>Ever (used Plone and) wanted to stop worrying about whether your site content has proper image scales generated for them? Here's a bobo traverser snippet that'll generate them on-the-fly: &lt;a href="https://gist.github.com/662563"&gt;&lt;span style="text-decoration: underline;"&gt;image.py&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Drop it in place of the ATImage traverser or use in your own content types.&lt;br /&gt;&lt;a href="https://gist.github.com/662563"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-4199623562418631224?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2010/11/on-fly-image-scales-with-archetypes.html</link><author>noreply@blogger.com (malthe)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-2372582923789642654</guid><pubDate>Thu, 29 Apr 2010 10:52:00 +0000</pubDate><atom:updated>2010-04-29T13:35:40.504+02:00</atom:updated><title>The mess Django's in</title><description>Adam Gomaa &lt;a href="http://adam.gomaa.us/blog/2007/aug/26/the-django-orm-problem/"&gt;is right&lt;/a&gt; that (when you don't &lt;span style="font-style: italic;"&gt;need&lt;/span&gt; to care about the database) – "Django gets the model definition language right".&lt;br /&gt;&lt;br /&gt;He continues to say "they're just using the wrong underlying library."&lt;br /&gt;&lt;br /&gt;This was back in 2007, but the situation hasn't changed much. It's a lot easier to use the Django ORM than SQLAlchemy for simple tables and relations. It makes all the technical details simply go away and for the target audience of Django, that's probably a good thing. Django gets it just right.&lt;br /&gt;&lt;br /&gt;Now if you don't really know how to use Django or if you want to use it slightly differently than how it was intended, and you take a peek under the hood, your impression of Django will change dramatically:&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;The code is awful.&lt;/blockquote&gt;I understand why people are attracted to Django. It's got a terrific story if you're willing to drink the kool-aid (basically it's Django's way or the high way and you shouldn't make any friends outside the circle of trust). You get a lot of things for free and you don't need to know all the details of all the routine problems.&lt;br /&gt;&lt;br /&gt;What I don't understand is how so many people can keep the secret that the code  is an outright horror. I sort of knew that it had to be, but I was in for a surprise.&lt;br /&gt;&lt;br /&gt;The short story is that shouldn't try to use Django from the inside; it's a pile of spaghetti with insane indirection and module dependencies and you're lucky if you manage to import anything at all. Every other function tries to import modules for you automatically and circular imports are the norm. It's all driven by convenience and convention, but if you're coming with your own expectations about how a system should or could work, you'll face only inconvenience and odd conventions.&lt;br /&gt;&lt;br /&gt;Even simple things like setting up and tearing down the database is awkward. You have to actually make an outside call to a command-line script to do it.&lt;br /&gt;&lt;br /&gt;Chris McDonough wrote recently about &lt;a href="http://plope.com/Members/chrism/import_time_side_effects"&gt;import time side effects&lt;/a&gt;. I think Django would be a mental buffer overrun. It kind of is for me, but I have now managed to set up a line of&lt;span style="font-style: italic;"&gt; import time side effect defenses&lt;/span&gt; that guard against most of Django's idiosyncracies.&lt;br /&gt;&lt;br /&gt;Rewrite?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-2372582923789642654?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2010/04/mess-djangos-in.html</link><author>noreply@blogger.com (malthe)</author><thr:total>34</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-6008478674297698921</guid><pubDate>Wed, 31 Mar 2010 05:15:00 +0000</pubDate><atom:updated>2010-03-31T13:07:22.342+02:00</atom:updated><title>Frameworks in Uganda</title><description>It's raining outside and I've still got half an hour to hold out for a window of opportunity. Traffic in this town is as bad as anywhere, but when it rains, it breaks down completely – traveling on two wheels is your only option. Yesterday, my boda-boda driver (the motorcycle taxi) failed to start his machine at first, and since he looked at bit young I asked him how old he was. "How can I know my age?" he replied.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As part of a charm offensive, our office has been tasked to deploy a demo application that runs on &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;. It's not &lt;a href="http://www.python.org/dev/peps/pep-0333/"&gt;WSGI&lt;/a&gt;, but it's not terrible either:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;  $ env/bin/python demo/manage.py runserver 0.0.0.0:8080&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This morning I was thinking about how much easier things are when you begin with &lt;a href="http://pythonpaste.org/webob/"&gt;WebOb&lt;/a&gt;, i.e. the raw protocol and a single layer of convenience. You're able to focus on the application environment and without much mental effort you're writing the beginnings of a test suite.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What I like about the &lt;a href="http://bfg.repoze.org/"&gt;BFG&lt;/a&gt; and &lt;a href="http://pylonshq.com/"&gt;Pylons&lt;/a&gt; frameworks is that they use this same basic foundation. You can evolve your application naturally from the just getting started phase to framework support. With Django, there's a ton of processing required to get set up, and it's my intuition that with all this setup, developers get late to the testing game. Test-driven development loses out to cargo-cult template-driven development.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I don't think I'll ever be happy on Django; I'm not even sure I buy into the notion of it being easier for beginners. Easier how? If it's about getting started writing your first spaghetti-application, then it's probably right on the mark. Heck, you don't even have to learn about relational databases. But this is 2010 and there's &lt;a href="http://code.google.com/p/scalaris/"&gt;Scalaris&lt;/a&gt; and &lt;a href="http://code.google.com/p/redis/"&gt;Redis&lt;/a&gt; and &lt;a href="http://cassandra.apache.org/"&gt;Cassandra&lt;/a&gt;. If I was just getting into programming, I'd want to use WebOb and one of these, throw in a URL dispatcher such as &lt;a href="http://routes.groovie.org/"&gt;Routes&lt;/a&gt; or &lt;a href="http://www.ottohttp.org/"&gt;Otto&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Django seems like a platform; I think the only platform you really need is the operating system. You might benefit from a framework, but you don't need it. Try and hold out on the framework decision and pull it down on your application only when it's a clear benefit.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-6008478674297698921?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2010/03/frameworks-in-uganda.html</link><author>noreply@blogger.com (malthe)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-4467466194123768700</guid><pubDate>Tue, 23 Feb 2010 07:50:00 +0000</pubDate><atom:updated>2010-02-24T14:47:18.590+01:00</atom:updated><title>Using Chameleon in Django</title><description>Using alternative template engines is a popular pastime these days and so I thought I'd give &lt;a href="http://chameleon.repoze.org/"&gt;Chameleon&lt;/a&gt; a spin on Django.&lt;br /&gt;&lt;br /&gt;Below is code for a template loader.&lt;br /&gt;&lt;pre style="font-size: 85%;"&gt; from django.template.loader import get_template&lt;br /&gt; from django.template.loaders import filesystem&lt;br /&gt; from django.template import TemplateDoesNotExist&lt;br /&gt; from chameleon.core.loader import TemplateLoader&lt;br /&gt; from chameleon.zpt.language import Parser&lt;br /&gt; from chameleon.zpt.template import PageTemplateFile&lt;br /&gt;&lt;br /&gt; def lookup(name):&lt;br /&gt;     return get_template(name+".pt")&lt;br /&gt;&lt;br /&gt; class DjangoPageTemplate(PageTemplateFile):&lt;br /&gt;     def render(self, context):&lt;br /&gt;         return super(DjangoPageTemplate, self).render(&lt;br /&gt;             context=context,&lt;br /&gt;             lookup=lookup)&lt;br /&gt;&lt;br /&gt; class Loader(TemplateLoader, filesystem.Loader):&lt;br /&gt;     is_usable = True&lt;br /&gt;     default_parser = Parser()&lt;br /&gt;&lt;br /&gt;     def load_template(self, template_name, template_dirs=None):&lt;br /&gt;         if not template_name.endswith('.pt'):&lt;br /&gt;            raise TemplateDoesNotExist(template_name)&lt;br /&gt;         source, path = self.load_template_source(template_name, template_dirs)&lt;br /&gt;         return self.load(path, DjangoPageTemplate), path&lt;br /&gt;&lt;/pre&gt;It makes two variables available in templates, &lt;span style="font-weight: bold;"&gt;context&lt;/span&gt; and &lt;span style="font-weight: bold;"&gt;lookup&lt;/span&gt;. You can use the lookup-function to retrieve other page templates without rendering them, e.g.&lt;br /&gt;&lt;pre style="font-size: 85%;"&gt;  metal:use-macro="lookup('main_template').macros['master']"&lt;br /&gt;&lt;/pre&gt;Note: &lt;span style="font-style: italic;"&gt;This code was written for Django trunk. Some imports have changed since the last release.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-4467466194123768700?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2010/02/using-chameleon-in-django.html</link><author>noreply@blogger.com (malthe)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-5962075637096170572</guid><pubDate>Fri, 15 Jan 2010 14:59:00 +0000</pubDate><atom:updated>2010-01-15T16:08:46.333+01:00</atom:updated><title>Don't trust the government</title><description>This came as a surprise: Everything you do inside a Zope 2/3 (Five) page template is trusted in the Zope 3 sense, and untrusted in the Zope 2 sense. As such, this is nonsensical:&lt;br /&gt;&lt;pre&gt; &amp;lt;span replace="context/@@my-protected-view|default"&amp;gt;&lt;br /&gt;  You do not have access to the protected view.&lt;br /&gt; &amp;lt;/span&amp;gt;&lt;br /&gt;&lt;/pre&gt;Fortunately, it's easy to restore order:&lt;br /&gt;&lt;pre&gt; from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile&lt;br /&gt; from Products.PageTemplates.Expressions import getEngine&lt;br /&gt;&lt;br /&gt; class UntrustedPageTemplateFile(ViewPageTemplateFile):&lt;br /&gt;     def pt_getEngine(self):&lt;br /&gt;         return getEngine()&lt;br /&gt;&lt;/pre&gt;This will make sure your view security assertions are actually respected.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-5962075637096170572?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2010/01/dont-trust-government.html</link><author>noreply@blogger.com (malthe)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-7106223605164368127</guid><pubDate>Mon, 07 Dec 2009 17:15:00 +0000</pubDate><atom:updated>2009-12-07T19:30:57.183+01:00</atom:updated><title>Default gateway</title><description>An HTTP response frequently contains hyperlinks to resources available through HTTP which are somehow internal the system. Examples include documents linking to other documents or stylesheets linking to images. It is not always the case that these resources are available from the same server. Static files are often served using a content delivery network.&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;Most web frameworks use the incoming request to generate URLs to other resources.&lt;/span&gt;&lt;/blockquote&gt;This works because the request contains various metadata about the HTTP request including which host it arrived to. In setups that involve proxies, it is often necessary to provide additional metadata (e.g. "x-forwarded-for") to make it work.&lt;br /&gt;&lt;br /&gt;The system works well for simple web applications. All resources stem from the same server, in our case we can imagine some WSGI application written in Python. We can deduce the application host URL from the request metadata (known as the &lt;span style="font-style: italic;"&gt;environment&lt;/span&gt;) and the rest is internal routing (using &lt;a href="http://routes.groovie.org/"&gt;Routes&lt;/a&gt; or another library that maps URLs to code or files).&lt;br /&gt;&lt;br /&gt;Whether the request is passed around throughout the code or made implicit through the use of thread-locals, the actual call signature for generating a URL is &lt;tt&gt;(resource, request)&lt;/tt&gt;. I think this pattern is wrong. We need to explicitly identify the &lt;span style="font-style: italic;"&gt;gateways&lt;/span&gt; that can serve up the resources internal to the system (with possible shades of gray in what's internal and remote). In a simple setup such a gateway may be created per-request from the request, but the abstraction should still hold.&lt;br /&gt;&lt;br /&gt;The call signature then becomes &lt;tt&gt;(resource, gateway)&lt;/tt&gt;. Note that a local consumer would provide the equivalent of &lt;tt&gt;localhost&lt;/tt&gt; and retrieve a URL that specifies the file protocol. For remote users there may be several possible gateways which we can prioritize based on &lt;span style="font-style: italic;"&gt;accessibility&lt;/span&gt; (e.g. physical location) or &lt;span style="font-style: italic;"&gt;availability&lt;/span&gt; (e.g. permission). An actual implementation might want to use &lt;tt&gt;(resource, service)&lt;/tt&gt; where &lt;span style="font-style: italic;"&gt;service&lt;/span&gt; represents some application mount point or URL spelling that is available on a particular gateway.&lt;br /&gt;&lt;br /&gt;To relate this to the WSGI protocol, applications will want to extract the following out of the HTTP request and do away with it:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Path&lt;/li&gt;&lt;li&gt;Payload&lt;/li&gt;&lt;li&gt;Remote user (and/or other session- or cookie data)&lt;/li&gt;&lt;li&gt;Metadata (e.g. language- or accept data)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;We can call this set of data the application-specific &lt;span style="font-style: italic;"&gt;request&lt;/span&gt;. Any such request should map to a set of gateways which may or may not be able to service some future request (keep in mind the goal is to produce the URL for some would-be request).&lt;br /&gt;&lt;br /&gt;Note that such a pattern would also help in writing tests. You do not need to produce a fake request in order to have a specific component render a response. Instead you need to define the "network reach" of your prospective client.&lt;br /&gt;&lt;br /&gt;Some people have the opinion that none of this matters much. In turn we often see weak abstractions which are hard to explain, but work because it's Python. The advent of Python 3 brings an opportunity to rethink our frameworks and libraries (because none of them work). Good abstractions help to keep things simple even if it is non-trivial to conceive of them. They're on honking good idea and I think we should have more of them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-7106223605164368127?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/12/default-gateway.html</link><author>noreply@blogger.com (malthe)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-8239238989163394050</guid><pubDate>Sun, 22 Nov 2009 21:08:00 +0000</pubDate><atom:updated>2009-11-22T23:29:18.576+01:00</atom:updated><title>Don't look back in anger</title><description>Next Thursday it will be a year since the release of Python 3. You've got to be out early in Christmas time which is my excuse for the untimeliness of this &lt;span style="font-style: italic;"&gt;rant&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;I thought I'd try to see what the fuss was about, i.e. does anything work? WSGI? It doesn't. While very informative, the &lt;a href="http://blog.dscpl.com.au/2009/09/roadmap-for-python-wsgi-specification.html"&gt;roadmap&lt;/a&gt; for the WSGI specification is also very unreadable. Let's see if we can extract some knowledge out of it!&lt;br /&gt;&lt;br /&gt;It seems to me that people sit with a copy of &lt;span style="font-style: italic;"&gt;Essential Python 2&lt;/span&gt; and try to see how to interpret the WSGI specification against an imaginary &lt;span style="font-style: italic;"&gt;Essential Python 3&lt;/span&gt;, e.g. "In Python 2 this was a string; what should–right, so bytes. Next, in Python 2 this was..." – to no end. Let's cut to the chase:&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;Rule 1: Strings should be strings, chunks should be bytes.&lt;/blockquote&gt;The roadmap then mentions that on Jython, sockets will return unicode. That's wrong, so that can be conveniently filed as a bug. It continues with another string prediction: "The status line specified by the WSGI application must be a byte string." Why must this be a byte string? It is obviously an actual string. I think it's even a Freudian slip to call it a "byte string". Please see rule 1.&lt;br /&gt;&lt;br /&gt;Then it gets a little unclear, but skipping ahead a handful of paragraphs, we come to this bullet point:&lt;span style="font-style: italic;"&gt; &lt;/span&gt;"For the WSGI variable 'wsgi.url_scheme' contained in the WSGI environment, the value of the variable should be a native string." I think this is what the rest of the world calls the &lt;span style="font-style: italic;"&gt;server protocol&lt;/span&gt;. If I can make a humble suggestion:&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;Rule 2: Please remove all proprietary keys from the HTTP environment.&lt;br /&gt;&lt;/blockquote&gt;Incidentally, the presence of these keys is probably what inspires developers to put all sorts of other proprietary keys in the HTTP environment. I have previously argued why this is &lt;a href="http://mockit.blogspot.com/2009/07/its-all-wrong.html"&gt;wrong&lt;/a&gt;. It occurs to me that when the WSGI specification says &lt;span style="font-style: italic;"&gt;environ&lt;/span&gt;, it means &lt;span style="font-style: italic;"&gt;request&lt;/span&gt;. What the application needs is the request which holds the HTTP environment and the content body. Everybody uses the term request for this; an HTTP request. It's convenient to split a request up in an &lt;span style="font-style: italic;"&gt;environment&lt;/span&gt;, which is the first few lines of the socket input and the &lt;span style="font-style: italic;"&gt;body&lt;/span&gt;, which is the rest. This body might be quite large, so the interface must be an iterable of binary chunks.&lt;br /&gt;&lt;br /&gt;Note that if we had a request object instead of this augmented environment, middlewares and frameworks that wanted to add touches of magic could wrap it or even change its class. Today they have to insert special string keys into a dictionary and explain how this isn't that wrong in their documentation (e.g. "it's better than a thread-local").&lt;br /&gt;&lt;br /&gt;Okay, this has turned sour. All I wanted was to try out Python 3. I'm not sure the current approach is going to make this any fun. The 2to3 solution is not appealing. It's a bit like an in-law staying temporarily in the house. When does it end? When is the try-import-except dance over? Am I ever going to import anything from the &lt;span style="font-style: italic;"&gt;functools&lt;/span&gt; module and feel comfortable about it? Here's a moratorium for you:&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;Rule 3: Forget Python 2.&lt;/blockquote&gt;From now on it's on the paying clients only list. Join the movement of full incompatibility and never look back! The downside is that we have to rewrite everything. I think it's worth it. Microsoft should have done it, Apple&lt;span style="font-style: italic;"&gt; did it&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Who got the better uptake?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-8239238989163394050?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/11/dont-look-back-in-anger.html</link><author>noreply@blogger.com (malthe)</author><thr:total>5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-7668109541203426777</guid><pubDate>Wed, 18 Nov 2009 17:24:00 +0000</pubDate><atom:updated>2009-11-18T18:49:26.119+01:00</atom:updated><title>Scheduling music using Spotlight and Python</title><description>Back in the last century, every decent music player had the &lt;span style="font-style: italic;"&gt;playlist&lt;/span&gt; at its center. People were religious about it because it wasn't just a practical device for music listening, it was your musical identity. Today most people are trying to come to terms with their 40+ gigabyte collection and need a musical &lt;span style="font-style: italic;"&gt;genie&lt;/span&gt; to manage it.&lt;br /&gt;&lt;br /&gt;Python to the rescue.&lt;br /&gt;&lt;br /&gt;Actually, the problem with Python is that the standard library is too rich. You end up writing a small multithreaded application complete with a command-line interface, when you merely set out to do something else for half an hour.&lt;br /&gt;&lt;br /&gt;My favorite music player on the Mac is the small application &lt;a href="http://www.voxapp.uni.cc/"&gt;Vox&lt;/a&gt;. It doesn't do anything, but it plays all formats and has an equalizer. For any given music track, I needed to know its duration, because this application wasn't going to collaborate with any notifications. I decided to try out my operating system's built-in indexing service, &lt;a href="http://developer.apple.com/macosx/spotlight.html"&gt;Spotlight&lt;/a&gt;. Turns out that I just needed to install some &lt;a href="http://sbooth.org/importers/"&gt;importers&lt;/a&gt; and then all my music was indexed. The duration was available from the query metadata.&lt;br /&gt;&lt;br /&gt;The resulting Python script allows you to take a list of song queries (I use "artist - title" which seems to work fine), save it to a plain text file and schedule it. There is a command-line interface which lets you skip and repeat songs.&lt;br /&gt;&lt;br /&gt;Source is available from the &lt;a href="http://github.com/malthe/mdplayer"&gt;repository&lt;/a&gt; (&lt;span style="font-style: italic;"&gt;as-is&lt;/span&gt;, BSD).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-7668109541203426777?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/11/scheduling-music-using-spotlight-and.html</link><author>noreply@blogger.com (malthe)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-4433996884499631327</guid><pubDate>Thu, 05 Nov 2009 23:29:00 +0000</pubDate><atom:updated>2009-11-06T11:56:24.399+01:00</atom:updated><title>Emperor's new clothes</title><description>The &lt;a href="http://wiki.zope.org/zope3/ComponentArchitectureOverview"&gt;Zope Component Architecture&lt;/a&gt; is often touted for letting you override so-called components which have already been registered elsewhere (by a library, out of your immediate control).&lt;br /&gt;&lt;br /&gt;It's &lt;span style="font-style: italic;"&gt;wrong&lt;/span&gt; (edit: to clarify, using the overriding facility of the ZCA is wrong, and by extension, to use the ZCA &lt;span style="font-style: italic;"&gt;because&lt;/span&gt; you can override components, is wrong too; I do not mean to suggest that the use of ZCA is misguided in general).&lt;br /&gt;&lt;br /&gt;Shrink-wrap software is a circumstance. If you must change it from outside (instead of &lt;a href="http://mockit.blogspot.com/2009/08/singing-and-branching.html"&gt;branching&lt;/a&gt;, which is a fine approach in many cases), just go ahead and update the functions or classes in question using the &lt;a href="http://mail.python.org/pipermail/edu-sig/2007-February/007787.html"&gt;reload approach&lt;/a&gt; (object identity changes should be avoided at all costs).&lt;br /&gt;&lt;br /&gt;There's nothing wrong with ZCA; it's in my view a misunderstanding to employ it for web application development at large. Rather, it's applicable for deployments that require live software component introspection. I don't know that web applications need this in general. What happens is that frameworks like &lt;a href="http://docs.zope.org/zopetoolkit/"&gt;Zope Toolkit&lt;/a&gt; and &lt;a href="http://www.plone.org/"&gt;Plone&lt;/a&gt; use these introspection features to map requests to code. That's a bit like using &lt;a href="http://en.wikipedia.org/wiki/Radio-frequency_identification"&gt;RDIF&lt;/a&gt; tags for consumption tracking (hint: require credit card payment or identity-based rebate instead).&lt;br /&gt;&lt;br /&gt;Most software is misunderstood. How to use it, when to use it. Sometimes it's worth the while to retrace your steps to learn why you ended up using a particular software.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-4433996884499631327?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/11/emperors-new-clothes.html</link><author>noreply@blogger.com (malthe)</author><thr:total>20</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-5552613818582895226</guid><pubDate>Tue, 03 Nov 2009 21:11:00 +0000</pubDate><atom:updated>2009-11-04T00:39:58.723+01:00</atom:updated><title>New in school</title><description>I've written an HTTP publisher!&lt;br /&gt;&lt;br /&gt;The most common reaction is: &lt;span style="font-style: italic;"&gt;why write a new framework?&lt;/span&gt; Well, it's not a framework. It's a little device that sits between the server and your code. It does more than &lt;a href="http://bobo.digicool.com/"&gt;bobo&lt;/a&gt;, less than &lt;a href="http://bottle.paws.de/"&gt;bottle&lt;/a&gt;. What it does, it does better than both.&lt;br /&gt;&lt;br /&gt;The name is &lt;a href="http://www.ottohttp.org/"&gt;Otto&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There aren't many moving parts, but the design is flexible enough to handle most use-cases. The syntax is agreeable, terse and very clear. Most importantly, it gets you going without any mental effort. There is no inversion of control. It is obvious at every step what happens, from request to response.&lt;br /&gt;&lt;br /&gt;The design has evolved entirely through examples, setting the library requirements instead of the other way around. The documentation is tested continuously using the &lt;a href="http://pypi.python.org/pypi/manuel"&gt;manuel&lt;/a&gt; package which keeps everything in sync and makes it possible to write out and test complete self-contained examples right in the documentation.&lt;br /&gt;&lt;br /&gt;That said, there isn't a lot to it.&lt;br /&gt;&lt;br /&gt;You can use the publisher directly as the basis of a web application, or integrate it into an existing framework. Suggestions or other feedback are welcome as comments are on the repository &lt;a href="http://github.com/malthe/otto/issues"&gt;tracker&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The publisher will grow a few more features (e.g. support for virtual hosting, static file helper) before its first release, but an effort is made to keep scope narrow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-5552613818582895226?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/11/new-in-school.html</link><author>noreply@blogger.com (malthe)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-9193927569565418042</guid><pubDate>Thu, 15 Oct 2009 22:53:00 +0000</pubDate><atom:updated>2009-10-16T01:16:00.885+02:00</atom:updated><title>The cure</title><description>A couple of years ago I wrote a small package called &lt;a href="http://pypi.python.org/pypi/z3c.jbot"&gt;z3c.jbot&lt;/a&gt; which made life as an integrator on Zope and Plone a lot easier. This is an advertisement for the latest version 0.5.&lt;br /&gt;&lt;br /&gt;New features:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No performance hit&lt;/li&gt;&lt;li&gt;It works with Chameleon&lt;/li&gt;&lt;li&gt;Replace images,  stylesheets and javascripts too!&lt;/li&gt;&lt;/ul&gt;With this release you can actually fully customize an out-of-box Plone site without writing a single line of code; replace the site logo, customize content templates and portlets, or change the included stylesheets.&lt;br /&gt;&lt;br /&gt;More information on the &lt;a href="http://pypi.python.org/pypi/z3c.jbot"&gt;project page&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-9193927569565418042?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/10/cure.html</link><author>noreply@blogger.com (malthe)</author><thr:total>7</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-6184959291017105446</guid><pubDate>Sat, 03 Oct 2009 10:24:00 +0000</pubDate><atom:updated>2009-10-03T13:39:31.146+02:00</atom:updated><title>Copying music left or right</title><description>I pirate music. Frequently. Most people do, too. It's not right in terms of &lt;a href="http://www.copyright.gov/"&gt;copyright&lt;/a&gt;; so let's talk about &lt;a href="http://www.gnu.org/copyleft/"&gt;copyleft&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;When we talk about music piracy, we usually think of it as a &lt;span style="font-style: italic;"&gt;free lunch&lt;/span&gt;. But we've been told many times over that there's no such thing. Money don't grow on trees; there are no free lunches. Won't the world stop turning if we give up copyright?&lt;br /&gt;&lt;br /&gt;'Lo and behold free software.&lt;br /&gt;&lt;br /&gt;I write free software, made available &lt;span style="font-style: italic;"&gt;as is&lt;/span&gt;, under the BSD license. My only source of income is the hours I clock from clients. The clients are interested because I write free software.&lt;br /&gt;&lt;br /&gt;The answer to music piracy is free music, as in copyleft. Everybody can hum, sing, dance and play along to music. To copyright music and sell it under a non-free license is artificial. It's no different than software, books or thoughts. Need a source of income? Work. Perform your music, or other people's music, sell it to advertisers (god forbid), sell merchandise to teenagers looking for an identity.&lt;br /&gt;&lt;br /&gt;There's just one problem. Record labels aren't interested; they are afraid that free music will hurt their business model. The irony is that it probably won't. They can still issue compact discs and charge for them. We have recently seen that the LP has grown popular again. There is money to be made from selling free music goods. I think there is money to be made from printing and selling free books, too (in fact, many older books are free; they are still being printed and sold for a profit).&lt;br /&gt;&lt;br /&gt;I think my music habits will stay illegal for the better part of this century. Things won't change. But when people complain "but how can you make yourself do it, knowing that the artists are starving from lack of income" my answer is:&lt;br /&gt;&lt;br /&gt;I don't starve.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-6184959291017105446?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/10/copying-music-left-or-right.html</link><author>noreply@blogger.com (malthe)</author><thr:total>8</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-4383679420107674654</guid><pubDate>Mon, 28 Sep 2009 15:54:00 +0000</pubDate><atom:updated>2009-09-28T19:18:09.321+02:00</atom:updated><title>Picking the right nose</title><description>Like or dislike, &lt;a href="http://docs.python.org/library/doctest.html#unittest-api"&gt;doctests&lt;/a&gt; formatted as restructured text (e.g. the venerable README.txt that resides in many packages) are a convenient way to document your software and make sure the documentation stays in sync with the actual codebase.&lt;br /&gt;&lt;br /&gt;It's surprisingly awkward to run these tests using &lt;a href="http://somethingaboutorange.com/mrl/projects/nose/0.11.1/"&gt;nose&lt;/a&gt;. After some debugging of the &lt;a href="http://docs.python.org/library/unittest.html"&gt;unittest&lt;/a&gt; module, the following is the workaround I've resorted to employ.&lt;br /&gt;&lt;pre&gt;import unittest&lt;br /&gt;import doctest&lt;br /&gt;&lt;br /&gt;class MyTestCase(unittest.TestCase):&lt;br /&gt;  def __new__(self, test):&lt;br /&gt;    return getattr(self, test)()&lt;br /&gt;&lt;br /&gt;  @classmethod&lt;br /&gt;  def test_readme(cls):&lt;br /&gt;    return doctest.DocFileSuite('README.txt')&lt;br /&gt;&lt;/pre&gt;The documentation for &lt;span style="font-style: italic;"&gt;nose&lt;/span&gt; suggests using the ``--doctest-extension`` command-line flag to use non-Python files as doctests, but it seems much more convenient to define them in the actual test module.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-4383679420107674654?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/09/picking-right-nose.html</link><author>noreply@blogger.com (malthe)</author><thr:total>6</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8212254010436871241.post-1597744852997108568</guid><pubDate>Sat, 26 Sep 2009 12:31:00 +0000</pubDate><atom:updated>2009-09-27T02:40:40.342+02:00</atom:updated><title>A new object database for Python</title><description>When Chris McDonough presents his &lt;a href="http://bfg.repoze.org/"&gt;BFG&lt;/a&gt; framework he uses the punchline "like Zope, but less". I'll take the liberty to reuse it about a new object database that I've written over the summer: "like ZODB, but less". It's called &lt;span style="font-style: italic;"&gt;dobbin&lt;/span&gt;, which is a reuse from another project, incidentally also an object database.&lt;br /&gt;&lt;br /&gt;Less code. About one twentieth. Of course, less features, too. And easier assumptions.&lt;br /&gt;&lt;br /&gt;I'll be the first to admit that I felt caught in the act when I first read the so-called &lt;a href="http://varnish.projects.linpro.no/wiki/ArchitectNotes"&gt;architect notes&lt;/a&gt; of the varnish proxy server. The author of that software claims most developers are still writing software like it was 1975. If you read that document and consider the memory management attempts of the ZODB, you might get the feeling that he's right.&lt;br /&gt;&lt;br /&gt;Dobbin is the logical consequence of that document. It doesn't try to manage its own memory.&lt;br /&gt;&lt;br /&gt;Less overhead. Persistent objects are read-only, until &lt;span style="font-style: italic;"&gt;checked out&lt;/span&gt;. Their state is shared between threads. This significantly reduces memory usage; in fact, memory usage has always been the Achilles' heel of the object database. This reduction comes with an inconvenience: objects must always be explicitly checked out before they can be changed.&lt;br /&gt;&lt;br /&gt;There's no inherent network support, but multiple processes can connect to the same database without configuration. There's no server process; the database is simply a file.&lt;br /&gt;&lt;br /&gt;Less complexity. Dobbin is written all in Python.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://pypi.python.org/pypi/dobbin"&gt;project page&lt;/a&gt; on PyPi has more information including a user's guide. It's not quite ready for serious usage yet. If you're interested in helping out, these are the next steps:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Packing (trimming away old versions from the transaction log)&lt;/li&gt;&lt;li&gt;Indexing (field-indexing and querying)&lt;/li&gt;&lt;li&gt;Persistent dictionaries and lists (buckets or similar)&lt;/li&gt;&lt;/ul&gt;To contribute code to the project you must sign the &lt;a href="http://repoze.org/contributor.pdf"&gt;contributor agreement&lt;/a&gt; for the repoze repository.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8212254010436871241-1597744852997108568?l=mockit.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://mockit.blogspot.com/2009/09/new-object-database-for-python.html</link><author>noreply@blogger.com (malthe)</author><thr:total>5</thr:total></item></channel></rss>

