[Web-SIG] Standardized template API

Phillip J. Eby pje at telecommunity.com
Fri Feb 3 20:57:44 CET 2006


At 11:17 AM 2/3/2006 -0800, Ben Bangert wrote:
>On Feb 2, 2006, at 11:49 AM, Phillip J. Eby wrote:
>
>>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.
>
>Since Pylons is just using Myghty, it still has full access to the
>WSGI call, so does RhubarbTart and Paste, so we'd all be set for this
>style. Recent discussion/patches to CherryPy indicate that they're
>putting in support to retain the full WSGI environ/start_response
>stuff so they'd be able to use it as well.

Great.


>>          # 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
>
>My main concern here, though its likely just a detail I'm not seeing.
>When you call the template engine with the WSGI environ, I'm a bit
>worried about URL generation. For example, Routes is WSGI aware, and
>if it sees SCRIPT_NAME, it'll prepend it to generated URL's.
>
>When you render templates, the template name in many cases has
>nothing to do with anything present in the URL. The URL might be / 
>comment/view/4, and the template rendered relative to the template
>root is '/viewers/comment.myt'. Myghty already has a WSGI handler,
>and has its own internal response/request objects, so its already
>suited quite well for the interface it sounds like you're proposing.
>However, to tell Myghty I'd want that path rendered, I'd have to set
>PATH_INFO to '/viewers/comment.myt'.

I think maybe there's some confusion here as to what I'm suggesting 
SCRIPT_NAME be set to.  I probably should've said that SCRIPT_NAME should 
represent the "consumed" part of the URL, and PATH_INFO should be empty 
unless there's some unconsumed path portion.  So if the URL path is 
/comment/view/4, then SCRIPT_NAME should be /comment/view/4 appended to 
whatever the original SCRIPT_NAME was, and PATH_INFO would be empty.

The purpose of this is just that some frameworks can potentially have 
unprocessed path segments following the URL that led to rendering of a 
template, and SCRIPT_NAME and PATH_INFO should reflect this, just as though 
the template were itself a WSGI application.  (Because it is one, and some 
"templates" may actually be whole applications "mounted" at the template 
location.)


>In this case, its possible Routes could still generate proper URL's
>as long as the SCRIPT_NAME only contained whatever was necessary to
>reach the WSGI app that ran the Route match. If SCRIPT_NAME is
>further messed with on the way to the template engine, the generated
>URL would be broken.
>
>For this reason, I think sending the request to a template engine via
>WSGI is fine, except SCRIPT_NAME should not be touched, since thats
>still where the "application" responding is located. Also, since
>PATH_INFO is now referring only to the template to be rendered, its
>un-reliable for purposes of determining the full URL.

My suggestion would be to add an extra WSGI key, maybe 
'wsgi.application_root' to represent the "original application SCRIPT_NAME" 
for frameworks that have such a concept.  Templates using Routes could then 
use that variable in place of SCRIPT_NAME.  It seems to me that Zope 
request/response objects also need this information, in order to generate 
the magic URL0-URL9 and other such variables.

The application root should of course be set at the entry point of the 
framework, so in the case of Routes, Routes could simply copy SCRIPT_NAME 
to application_root in environ if there isn't one already set.  It could 
then simply use application_root first when generating URLs, and for that 
matter it could add extension APIs to the environ to allow accessing Routes 
APIs from embedded apps.


>Actually, now that I think about it, if we want to use WSGI for the
>template engine, I think it'd better to put additional keys in the
>environ for what template path to render, etc. This way vital
>information for URL generation isn't altered in ways that might
>result in broken URL's.

I'd like to preserve the normal WSGI invariants instead, because this 
allows entire mini-applications with their own URL space to be embedded as 
"templates" within a containing application.  Such apps can then rely on 
SCRIPT_NAME as being their root, even if they weren't originally written 
for embedding.

I don't see a use for including a template path anywhere, and that really 
wasn't what I was suggesting.  Locating templates' implementation data is a 
job for the enclosing framework, and it's not really the template's 
business to know about that.


>>      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
>
>Looks fine to me, except for the concerns I cited above for how the
>template engine should determine the template to render.

The template engine wouldn't; the framework simply hands the engine the 
"template" source (as a string or a stream) and gets back an app object 
like the above.  See my "trivial counterproposal API" for a summary of the 
engine interface.

As we flesh out these details, I'm realizing that what I'm actually 
proposing might be best described as a "WSGI Embedding" standard, that 
describes how a framework can use an "application factory" to obtain a WSGI 
app from a string or stream.  Wrapping a template engine as an application 
factory makes it possible to embed active pages in any framework that 
supports WSGI embedding, and supporting WSGI embedding in a framework lets 
you run any WSGI application inside it that has an application factory 
implementation.

So, we're basically solving the old "How do you deploy/configure a WSGI 
app?" question, not by having a single file format for deployment, but by 
allowing pluggable file formats, some of which just happen to be "templates".

Meanwhile, view-oriented frameworks like Zope 3 and peak.web can basically 
embed entire applications or sub-applications wrapping published objects, 
and even simple servers like the mod_python WSGI server could serve 
templates and applications straight from the file system.  And even 
controller-style frameworks that use templates strictly for postprocessing 
will end up being able to embed fairly sophisticated things.


>>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.
>
>Yep, makes sense to me, especially since Myghty already does this.
>
>>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.
>
>Excellent. :)

When WSGI was created, I had no idea that people would come up with cool 
stuff like Ian's debugging and lint middleware components, so I'm really 
excited thinking about what kinds of things people will be able to do with 
WSGI embedding.



More information about the Web-SIG mailing list