Python Programming, news on the Voidspace Python Projects and all things techie.


How Jalopy Works

emoticon:restart If you want to integrate a WYSIWYG HTML editor with a web application, you could do a heck of a lot worse than Kupu. It's a Javascript application that runs in the browser to edit HTML pages. Obviously in order to use the created/edited page it needs to be integrated with the server. Jalopy is a tool to allow a group of people [1] to maintain and create a set of webpages. This is an effective way of sharing information on an Intranet or the web. Because it runs as a CGI it doesn't need a complicated web application server installing [2].

It's written in the best web application language Rolling Eyes . If you're writing a Python web app, and are considering using Kupu, you might find it useful.

Jalopy is a very simple web app. This brief article covers the basics of the Jalopy flow control. It will help you understand the Jalopy source code. The online docs for Jalopy explain how to setup and configure Jalopy. Doing that successfully is the first task if you want to understand how it works.

If you are merely curious, and want to have a play; try out the online demo.


When jalopy is run ( it calls the main function from, which is the real heart of Jalopy.

First we create the cgi form instance :

theform = cgi.FieldStorage()

This tells us what Jalopy needs to do - it contains the information sent from the browser to the CGI application.

Jalopy is configured to be able to handle several different 'sites' off a single install, so it needs a site parameter. In this is :

thesite = 'jalopy'

We read the configuration file for the site. This is done using the readconfig function in It sets up a whole load of global variables - which represent the configuration options for this site. All config operations are done using ConfigObj. This is not a very good way of setting up config options - I should use a config data structure and put the main body of Jalopy in a single class.

Logging In

Then main is called. This calls the logintools function login.

# if userdir is set - do the login stuff.
# This could include new login, checking the cookie
# or even admin stuff - all transparent
if userdir:
    from login import login
    action, userconfig = login(theform, userdir, thisscript)
    # this function displays login and exits if it fails,
    # otherwise it prints the new/updated cookie

    username = userconfig['realname']

logintools [3] is actually a framework for handling user authentication for CGI applications. It does this transparently to the calling application. If the user isn't logged in, it presents them with a login screen. If the application is configured to allow user registration, it will present them with an option to do that. After displaying the login screen it calls sys.exit().

If they are already logged in (it uses a cookie), or they perform a successful login, then this function returns a config object that represents information about that user. This includes details like their name, admin level, the last time they logged in, and so on.

Into Jalopy

Still inside the main function. Having checked the user login, the main function checks what action is being performed by the parameters inside the CGI form instance. The options are :

  • edit a page
  • send a page to edit
  • save an edited page
  • display edit page details page
  • do the edit page details
  • delete a page

If no parameters have been provided then the index page is displayed. This allows the user to choose what to do next - in which case a form submission with the appropriate parameter will be sent.

Each of the above options calls a function. From this you can see the structure of the Jalopy program. These functions are the basic blocks of Jalopy.

Editing a Page

The real purpose of Jalopy is to allow you to edit pages. This uses the Kupu javascript editor. An example HTML page, for editing web pages using a FORM, is included as part of the standard Kupu distribution. All I needed to do was edit this so that it referenced a page sent to it by Jalopy, and made the form submission to the right place. This page handles all the references to the Kupu editor.

Assuming we are editing a page, Jalopy sends the HTML page with the Kupu editor. This has an IFRAME where the editing is done. Kupu doesn't edit the page directly - the iframe points to Jalopy and one of the parameters tells it which page it wants to edit. Jalopy then fetches the right page, processes it, and sends it to Kupu. Doing it this way allows us to process the page before sending it to Kupu.

This is why send a page to edit is one of the options in Into Jalopy.

When the form is submitted, the edited page is sent back to Jalopy. This triggers save an edited page.

And that's about it Smile . It's all quite simple really. A few interesting things happen along the way - the public and private index pages have to be updated for example - but nothing too complicated.

The next thing to add to Jalopy, is recording who made changes (and when), and allowing the admin to roll back any mistakes.

Things to Know

  • Kupu needs the pages in UTF8 character encoding.

    This means lots of encodes and decodes throughout the program. Writing Jalopy was how I learnt about character encoding (which isn't as difficult as it first seems). It could probably do with a good cleanup.

  • Because of the way Kupu works, Jalopy will only work with Mozilla/Firefox or Internet Explorer browsers.

  • Correct values (like URL paths, page names, etc) are inserted into the HTML pages using a simple templating system. This uses a lot of values like **some name**, which get replaced with the real value at run time. You'll see a lot of this in the code.

  • ConfigObj is used a lot through the code. It's generally used for storing config data, but because it has simple methods for reading [4] and writing [5], it's a very handy way of storing information. It's kind of like a persistent dictionary.


[1]Or an individual - but it's targeted at collaborative websites.
[2]Any server with Python 2.2 or more recent will do. This includes a lot of cheap Virtual hosting accounts.
[3]Written by me Smile . See
[4]config = ConfigObj(filename) reads and parses a text config file. You can then access keywords and values like a dictionary.
[5]config.write() then writes any changes back out to file.

Like this post? Digg it or it.

Posted by Fuzzyman on 2005-06-17 08:20:41 | |

Categories: ,



emoticon:python There is a new version of rest2web [1] available at Voidspace, in SVN, and at Sourceforge.

This version adds something called uservalues to rest2web. It allows you to create values that can be used by the templating system, and to specify another file to be used as the body of the page. If that body uses your uservalues, it is easy to have several files using the same body - but inserting different text into it.

One obvious use for this is having multiple translations of the same site.

See uservalues for the lowdown and translation pages for a trivial example. The source of the example is included in the distribution - so you can see how it's done.

For those who don't know, rest2web is a website templating system optimised for storing content in reST format. It can autogenerate navigation links and sidebars for you, as well as sporting a flexible templating and macro system. See the online docs for more details than you could possibly want.

[1]We're now up to 0.2.2

Like this post? Digg it or it.

Posted by Fuzzyman on 2005-06-15 14:56:47 | |



Textmacros for Docutils

Very Happy How about that for a sensible title, eh Question .

This post is to announce two things. First of all my all new Firedrop2 Section [1] is up and running.

It includes my own distribution called The Fuzzy Version. This is a temporary fork whilst Hans approves the changes I've made. The main change is improved reST support. This requires docutils 0.3.9.

The new section has docs on templating, macros, options, plugins, and more.

I've broken out the textmacros module from the Firedrop project. This system is also used by rest2web and provides an easy way of extending docutils (or any other text based system).

It maps markup like {name;param;param} to function calls and replaces the text with the output. It can also apply transformations to whole passages of text using a {+name} some text here {-name} syntax.

See the textmacros page for download and use details.

It's very simple though - an script will process directories of files. I recommend using it on the output of docutils files [2]. You can use it for adding acronyms, smilies Evil or Very Mad , or even doing Python source coloring.

# if the macro is not in the namespace, we ignore it
macroname = t[2][1:-1].split(';')[0]
if macroname.startswith("+") or \
     macroname = macroname[1:]
     if self.namespace.has_key(macroname):

It comes with an example macro file, and it's very simple to add new ones. For full docs see : The Macro System [3]

[1]Firedrop2 being the blogging tool for discerning pythoneers, written by Hans Nowak.
[2]I've only ever used it with HTML - it may be just as useful with Laytex.
[3]Part of the Firedrop docs.

Like this post? Digg it or it.

Posted by Fuzzyman on 2005-06-15 13:34:30 | |

Categories: , ,

Hosted by Webfaction