2011-09-22

Python, long words and the soft hyphen

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:
The soft hyphen tells the user agent where a line break can occur.
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.

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.

The following Python function inserts soft hyphens into a text string, guided by a hyphenation dictionary:

If you can't see the script embedded above, you can see the source here.

"Less.app" on linux

From the homepage:
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.
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.

On the Mac, there's Less.app. 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.

On Linux, the equivalent is a few lines of bash: Note that you must have less.js (via node.js) and inotify-tools installed.

If you can't see the script embedded above, you can see the source here.

2011-07-14

Speed up your Plone 4 site with Chameleon

The fast template engine that runs on just about any Python platform version 2.5 and up now runs on Plone 4!

It's already running live in production on Enfold's Ploud infrastructure where they see a consistent 20% or higher increase in performance.

To get Chameleon running on your site, simply add a dependency on five.pt and make sure you get version 2.1. Plone's automatic package configuration does the rest.

eggs =
...
five.pt>=2.1

Support for Zope 2 security and restricted Python is included.

It's not just about speed.

Other good reasons to use Chameleon are:
  • Easier debugging – cuts out most of the noise from stack traces
  • Less dependencies – uses only the standard Python library
  • Flexible parser – supports non-compliant markup and SGML
  • Works with any framework on almost all Python platforms
Please report any issues on the bug tracker.

2011-03-02

Writing a single-source library for Python 2 and 3

The recently released Chameleon template compiler was written as a single source for all Python platforms > 2.5, including Python 3.x (and PyPy).

I'd like to share my experience in taking this approach instead of using the 2to3 tool or a similar technique (read this article by Armin Ronacher to compare).

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.

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 sys.exc_info() 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 unittest2.

It's hard to avoid conditional imports and use of various aliases such as:
  try:         fast_string = str         str = unicode         bytes = fast_string     except NameError:         long = int         basestring = str         fast_string = str
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.

In terms of packaging, I decided to require distribute. I don't know what the support for Python 3 is with setuptools, 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 compatibility list.

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.

2011-02-22

Chameleon on Python 2, 3 and PyPy

This is to announce that a new installment of the Chameleon 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 Zope Page Templates language. There are no hard library dependencies.

To try it out, install it from PyPi:
  # easy_install Chameleon
Or get a copy from the repository:
  http://github.com/malthe/chameleon
You can report bugs on the issue tracker. Chameleon is the default template engine for the Pyramid 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.

2011-01-27

HTTP response proxy with Zope 2

You sometimes want to proxy an HTTP object through your site.

If response is your urllib2 response object, then for Zope 2 to actually accept it as a proper downstream response, you need to apply this little trick:
  from zope.interface import alsoProvides
from ZPublisher.Iterators import IStreamIterator
alsoProvides(response, IStreamIterator)
Without the interface idiosyncrasy, Zope might have just checked for a read method on the response object and be done with it.

2010-12-12

Getting registry settings in Plone to display in fieldsets

Although still a little rough around the edges 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.

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.

This proved to be somewhat out of the ordinary for plone.registry. It includes a records proxy class which neatly does the mapping between the interface and the registry. The following gist includes two points of interest in particular: an abstract 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.


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".