super-thin WSGI-based Python Web Framework by Joe Gregorio - see 2006-10-01-GregorioDisposable Python Web Framework

Feb22'2007: I'm going to try to migrate the PikiPiki WikiEngine to this. Goal: Clone Zwiki

  • no Data Base, not much structure to content (though the File System IO will go here, I guess), so ignoring the for now plus dbconfig and


    • I have Selector in place, but it's a bit behind, so update it

    • one of my goals is to easily support Multiple Thinking Spaces, so have to design URI structure/mapping...

      • hmm, actually I don't think that's an issue here - I'm not mapping to a different method per space, so within the actual app code I can access the domain/host/path params to decide which space I'm working in...

Apr3 (I've been busy)

  • decide to "start" by ripping out all the kid and SqlAlchemy bits from the example files. Then launch the listener, get no errors. Hit the server, and get 404 error back. Perfect!


  • have established that WSGI environ variables hold lots of what I'll want in determining which NameSpace I'm in: 'HTTP_HOST', 'PATH_INFO', 'SCRIPT_NAME'...

    • info on wsgi.routing_args


  • now delivering the unrendered content, from a single NameSpace


  • forking bits of PikiPiki code to conform to this model

  • it's rendering the WikiText nicely, but

    • it's "printing" the same Front Page from a different NameSpace in the terminal window

      • the 'import' was running the whole thing - once I put the main piki bits inside a 'name=main' test that went away
    • it's not linking a Wiki Name to the existing appropriate page (probably looking in the wrong NameSpace)


  • put same htdocs logic in code as in - now rendering proper page links!

    • though it's got the wrong script in the urls it generates.

      • tweaked link_tag() and that's fine
  • but link to non-existent page returns "server error" page with no error logged in terminal window - that's from model.page_get()::

    File "/Users/billseitz/Documents/flux/flux/", line 9, in page_get f = open(doc_path, 'r') I O Error: [Errno 2] No such file or directory: '/Users/billseitz/Documents/flux/flux/htdocs/Second Page'

  • it probably makes sense to decide how to handle this within view.page_get()


  • decided to handle the normal Edit-form-deliver before handling the page-not-found case, as the latter will probably just give an edit-form

    • PikiPiki works that way. Zwiki does not: it wants you to only create a new page by following a link from an existing page. In some ways that does make more sense (esp since the create-orphan-page model can lead to an island if it doesn't include a WikiWord in it)


  • was being driven crazy by Selector seeming not to work to get to my edit_form, then finally realized that somehow I'd duplicated the bulk of the code, so the edits in the first copy were being eliminated by re-creating the object in the 2nd copy. Duh.


  • what kind of URI do I want for the edit form: '/Page Name/edit_form' (which Zwiki uses) or '/Page Name/;edit_form' (which the Robaccia examples uses) or '/Page Name;edit_form' (which seems right to me, treating the edit form as a representation of the page document)?

    • also, noticing that the Robaccia example submits a change by doing HttpPost to the edit_form, rather than the document itself. Hmmm.... I see that Luke Arno's WIP WikiEngine example does the same thing. So I guess I'll bow to that.


  • it definitely looks like Selector jumps to the 1st URI expression match. Therefore the specific Edit URI needs to come before the get-page URI that is a subset. Joe's example page doesn't seem to be ordered that way.


  • it looks like nothing installed so far provides a nice dictionary of form-field data. Should I load Luke Arno's YARO] Python Paste has a 'parse_formvars' function in paste.request which just takes the WSGI environment and calls the cgi module (the Field Storage class) and turns that into a Multi Dict. I'm actually just ripping out parts of that function from YARO. But I'm getting a weird error::

     File "/Users/billseitz/Documents/flux/flux/", line 54, in form_parse
        if isinstance(value, list):
     Type Error: isinstance() arg 2 must be a class, type, or tuple of classes and types 
    • finally decided to rip out that chunk, and assume for now that won't be facing any multi-value fields. Used this code to only take the first value if it comes up.


  • got the page_update working, with redirect back to page when done

    • but not logging change for RecentChanges (is that even really necessary, or can I just do a directory listing?)


  • create-page link is now just going to same format of URI as getting existing page

  • catch I O Error on getting the file, and deliver edit-form

  • but then HttpPost is going to wrong place.

  • is this the wrong approach? Should I be pointing initially to an edit-form? Yes, will change that rendering.

  • yes, that's better


  • but what if request is for page that doesn't exist? Render edit form? No, just make page-not-found.

  • but if use regular template, then edit up with Edit button, which we don't want.

  • so made not_found function with just 1-line body


  • have decided to make simplest possible RecentChanges to Clone Zwiki - so won't make a changelog, just generate directory listing in mod-time order.

  • but os.listdir only gives you names, with no mod-time.

  • there are a variety of examples involving stepping through every file in a directory to get its info.

  • but if I have a directory with thousands of files, and just want the last 20-50 of them, that smells awfully inefficient.

  • am I going to use 'commands.getoutput()' to call an 'ls -ltT' function and then parse the results?

    • only need the file/page names. Then I can get the mod-time of just the newest file if I want that for ETags purposes, etc.

      • actually will want the mod-time for a number of most-recently-changed files for RSS. But that's still ~20 files instead of thousands.


  • Yes, using os.commands() to call ls; then using os.stat() to get mod-time of most recent files (because the dates included in the ls can be rather inconsistent in rendering).

  • Probably time to find a CSS stylesheet somewhere.

  • but to deliver it, I have to support a static page delivery method

    • and images too, i guess - actually I'll plan on using Amazon S3 for that.


  • assuming URI with '.' in it is static; that works.

  • put ref to CSS sheet in head of template

    • now watch it get hit for every single page - I would have thought the browser would cache that like an image. Apparently not. Definitely going to want ETag working, but not worrying about it for now. (Could even just use Amazon S3 to deliver that, I suppose.)

      • for that matter could plan on using Amazon S3 for all static pages. But probably not.
  • hmm, static page has not Edit button; if tweak the URI to have the edit bit at the end, it doesn't work. Do I want that to work? Or is this rare enough that I'd just use FTP or something to upload static stuff? Will assume that for now.

  • what about images? That would probably be a good reason to go with Amazon S3, at which point I might as well stick the CSS page in there, too.

  • actually, should probably just plan on using "real" Web Server like Apache as Proxy Server and to handle static content.


  • have RecentChanges fork for RSS feed. It uses the right tags.

  • need to add guid, smells like just mirrors the link

  • but need to escape (or do I mean encode?) the HTML.

    • it seems like people just use 'cgi.escape()'

    • I should also be escaping content when saving it, for Security purposes, but for now this meant to have a single person with write priv, so can add that later.

      • you have to look out for double-escaping



  • validating RSS...

    • doh! forgot to close 'item'

    • had to change 'pubdate' tag name to 'pubDate'

    • had to make an email address

    • passed!

  • what's next?

    • go back to work on CSS page?

    • authentication?

    • settle SmartAscii flavor decision?

Aug09 - considering SmartAscii choice


  • not loving any of the choices, going to stick with Structured Text since that's the content I have and it's not horrible.

  • use Easy Install to install zope.structuredtext - it works interactively

    • hmm, but generates a whole page/document of HTML, including header/etc when I really just want a body to insert into a template. I wonder whether that's controllable?

      • ugh doesn't look like it. Do I (a) edit the underlying library to skip that stuff (or have an option to skip it), or (b) leave it untouched and strip the output in a separate function in my own library? Probably (b).

Why did I stop this? I think I got wary about regretting later not having some fuller-framework features...

Edited:    |       |    Search Twitter for discussion