[Web-SIG] Standardized template API

Phillip J. Eby pje at telecommunity.com
Thu Feb 2 20:49:24 CET 2006

At 01:48 PM 2/2/2006 -0500, Michael Bayer wrote:
>Can those of us who
>have worked less with "the high end" see some real examples of what
>they need, and how they will be marginalized by a template adapter

Have you ever used PHP?  ASP?  DTML?  Specifically, have you ever used them 
to generate any content-type other than HTML?  This is a trivial example of 
a use case that a vars'n'strings approach doesn't support, without 
basically reinventing a new protocol that duplicates WSGI.

I totally understand that for the frameworks where the current 
vars'n'strings proposal originated, this is a non-issue because they always 
have Python code between the framework and the template.  But there are 
plenty of frameworks (and templating engines) where what you want is to 
*just have a template* in order to implement a URL, either as a method of a 
published object, or just as an "active page".

The vars'n'strings approach can't do active pages, the WSGI approach can.

>Should those of us concerned about WSGI maybe try out a WSGI- centric idea 
>and see how that goes ?  Even though I am skeptical of
>it, I've hardly any concept of what it would even look like.

For frameworks like TurboGears that treat a template as a formatter of the 
return value of some Python code, the difference wouldn't be 
user-visible.  And for frameworks, servers, or tools that use WSGI 
internally now (e.g. Paste, Routes, maybe Pylons?) there might not be any 
implementation to do at all, except to add support for loading/compiling 
resources.  These tools can already run WSGI apps, they just need support 
to allow mapping URLs to templates.

Tools that don't do WSGI yet internally would have to add a WSGI "server" 
component that creates an environ dict and add a start_response/write/iter 
facility.  These aren't that complex, and if the framework is itself a WSGI 
application, it can simply pass through a modified version of the 'environ' 
it received from the original WSGI server, along with the 'start_response' 
it received.  It then has to simply return the template's return value to 
the WSGI server.  In short, the framework just has to act like WSGI 
middleware.  A trivial example:

     def framework_app(environ, start_response):

         # framework-specific code to parse environ and figure out
         # where the URL points to, updating SCRIPT_NAME and
         # PATH_INFO as it goes, so SCRIPT_NAME points to the template
         # when done, while adding any framework-specific variables to
         # environ.

         if found_a_template:
             # framework-specific code to figure out what template
             # engine the template uses

             # ask the engine to load a WSGI app from a file
             # (or wherever)
             app = engine.compile_stream(open(filename,'r'))

             # Run the app against the original environ/start response
             # and return its return value, unless the framework needs to
             # alter the output some way (in which case it should do normal
             # WSGI middleware stuff).
             return app(environ, start_response)

Now, if you compare this to what you have in the case of vars'n'strings, 
you'll notice that one thing this code is *missing* is the code to set a 
default content type, status, etc., while dumping out the "string".  In the 
WSGI approach, that code moves to the *template* side of the fence.  If the 
framework needs to add or modify headers, it can do so by passing in an 
altered start_response, e.g.:

     def my_start(status,headers):
         # framework-specific code here to munge headers
         return start_response(munged_status, munged_headers)

     return app(environ,my_start)

Does this put more burden on framework developers?  Probably so.  It will 
be the most burdensome for frameworks that don't carry WSGI deep inside 
themselves, or whose APIs don't provide any way to do the things WSGI 
allows.  They may have to write code that recreates WSGI from an internal 
request or response object, possibly containing already-parsed form data 
and cookies and such.  Or, they may simply need to move their traversal or 
routing logic nearer to their WSGI input, so that any framework-specific 
request/response objects are created "just in time".

Does this put any significant burden on template developers?  Probably 
not.  The most trivial template wrapper would consist of something like:

     def trivial_template_app(environ, start_response):
         output = ["some %(someVar)s text" % environ['wti.source']]
         start_response("200 OK", [('Content-type','text/html')])
         return output

Templating tools are then in a position to offer response-management API 
directly.  For example, a ZPT wrapper could offer Zope-style 
REQUEST/RESPONSE objects for use in the template, because it would be 
dealing with WSGI.

The single strongest argument that I think can be made *against* the WSGI 
approach is quite simply that I'm asking framework developers to help make 
their frameworks obsolete, by moving their request and response objects to 
the periphery of their frameworks, so that developers have not only a 
choice of template *syntax*, but also a choice of request/response APIs 
associated with those templates.

Perhaps that's an unrealistic idea; maybe it's too soon to push for WSGI 
adoption phase 2 (the de-frameworkification of the frameworks).  Maybe the 
only realistic consensus at this point in time is a niche API for 
vars'n'strings.  Maybe the only way to showcase the power of what I'm 
proposing is to make WSGI wrappers for some template engines and implement 
the load/compile/save API I proposed on some server-side stuff.  I just 
don't want to end up in the position of having spent time to write Yet 
Another Framework, as opposed to contributing code to a common standard.

More information about the Web-SIG mailing list