A Python web framework that makes the most of the filesystem.
Simplates are the main attraction.

Virtual Paths

Aspen supports dynamic URLs using virtual paths, which are specially-named directories and files on your filesystem.


Make a directory on your filesystem called %name.

$ mkdir %name

Then make an index.html.spt simplate in there with this content:

Greetings, {{ path['name'] }}!

Now hit http://localhost:8080/aspen/. You should see this:

Now hit http://localhost:8080/python/. You should see:

Get it?


Aspen will also match files that start with a percent sign (%). Make a simplate in %name named %cheese.txt, with this content:

{{ path['name'].title() }} likes {{ path['cheese'] }} cheese.

Now test it out:

Virtual path files only work for the last URL path part, so if you hit /chad/cheddar.txt/ (with a trailing slash), you’ll get a 404:

Virtual path files (only! not directories!) are greedy, however. so if you hit /chad/swiss/gruyere.txt then since it ends in .txt and there's no real swiss directory to take precedence, the %cheese.txt file will be used, with cheese equal to swiss/gruyere .

The general philosophy of aspen's matching with virtual paths and greedy virtual filenames is Most specific wins, so if there's a real directory named swiss with a file named gruyere.txt in it, then that real file will be preferred over the virtual one.


By default, path parts are decoded to Python unicode objects using ASCII, and are then unquoted (per urllib.unquote). You can also typecast path parts to arbitrary objects, by registering typecasters in the website.typecasters dictionary in your A typecaster is a function that takes two positional arguments, the path part as a unicode and the state dictionary from the current algorithm run, and returns an object. Typecasters for int and float are included out of the box.

Make a directory called (for files, put the cast before the file extension, like

$ mkdir ""

Then put an index.html.spt in there with this content:

Tonight we're going to party like it's {{ path['year'] }}!

Now hit http://localhost:8080/1999/. What do you get?

Wait ... where's the party?


You can only have one variable directory per level. If you have more than one, the case-insensitive alphabetically first is used. Get it?

Remove the %name directory:

$ rm -rf %name

Now refresh, and you should see:

That’s better. Yay filesystem!