[Web-SIG] My original template API proposal

Ian Bicking ianb at colorstudy.com
Mon Feb 6 00:15:22 CET 2006


Phillip J. Eby wrote:
> At 02:46 PM 2/5/2006 -0600, Ian Bicking wrote:
> 
>> Ian Bicking wrote:
>> >       def render(template_instance, vars, format="html", 
>> fragment=False):
>>
>> Here I can magically turn this into a WEB templating spec:
>>
>> def render(template_instance, vars, format="html", fragment=False,
>> wsgi_environ=None, set_header_callback=None)
>>
>> wsgi_environ is the environ dictionary if this is being called in a WSGI
>> context.  set_header_callback can be called like
>> set_header_callback(header_name, header_value) to write such a header to
>> the response.  Frameworks may or may not allow for setting headers.  If
>> they don't allow for it, they shouldn't provide that callback (thus
>> headers will not be mysteriously thrown away -- instead they will be
>> rejected immediately).  [Should set_header_callback('Status', '404 Not
>> Found') be used, or a separate callback, or...?]
>>
>> This follows what all "server pages" templates I know of do.  That is,
>> they do not have special syntax related to any metadata (i.e., headers)
>> or even any special syntax related to web requests.  Instead the web
>> request is represented through some set of variables available in the
>> template.
> 
> 
> Yes, but different template systems offer different APIs based on it; 
> the idea of using WSGI here was to make it possible for them to offer 
> their *own*, native APIs under this spec, not to force the use of the 
> host framework's API.

There's nothing that specifies what the template does with vars.  It 
might be reasonable, for instance, in ZPT for the global ("context") 
variables to be build from wsgi_environ, and the vars dict to be put in 
as "options".

> The only thing that's missing from your proposal is streaming control or 
> large file support.  I'll agree that it's an edge use case, but it seems 
> to me just as easy to just offer a plain WSGI interface and not have to 
> document a bunch of differences and limitations.  OTOH, if this is what 
> it takes to get consensus, so be it.

We could change the return value of render to be an iterator.  I don't 
see any problem with this, as it's so easy to do ''.join(return_value), 
or return [content].  I do *strongly* feel that templates should be 
allowed (and encouraged) to return unicode strings.

There's also the possibility of returning values other than strings, 
though, like an ElementTree object.  I think this is interesting, and 
the fallback if strings are returned is pretty easy -- the template 
consumer should just make sure they handle strings in addition to 
whatever they asked for (which just means parsing the output into an 
ElementTree object in this case).  Returning an iterator makes this harder.

There's probably more likely performance benefits in returning 
ElementTree objects (or similar) for use when chaining transformations, 
than there is in returning iterators for large content bodies.  Maybe 
this could be handled with two methods instead of the one render(). 
Which actually is what the original TG spec has (though I'd like the 
spec to indicate the string fallback implementation).

Well... another option is just to expect consumers to try to get a 
method (e.g., render_elementtree), catch AttributeError, and fall back 
that way.  That seems the most straight-forward.

> The additional advantage to using plain ol' WSGI as the calling 
> interface, however, is that it also lets you embed *anything* as a 
> template, including whole applications if they provide a "template 
> engine" whose syntax is actually the application's configuration.

The template plugin can do whatever you want, if it takes string content 
and returns string output.

With the WSGI-based spec, for some cases (e.g., not in a web 
environment) you have wrappers that create a pretend  WSGI environment 
and wrappers that cover up the WSGI response.  In the TG model, you have 
a wrapper that makes a WSGI application from the plugin, or presents a 
template-like interface to a WSGI application.

Both are fairly simple wrappers.

Some aspects of the WSGI spec can remain as suggestions -- for instance, 
if you are wrapping a WSGI application, we can suggest that you put vars 
into 'wti.vars'.  This doesn't have to be built on WSGI in order to 
suggest in the spec how it would interact with WSGI.  Just like we can 
suggest a setuptools entry point group, without building this on setuptools.

> Anyway, the only differences I'm aware of between what you're proposing 
> and what I'm proposing are:
> 
> 1. Syntax sugar (each proposal sweetens different use cases)`

In addition to sweetness, there's the question of comfort.  Will you 
have to understand WSGI to understand the spec?  How comfortable will 
people feel implementing the spec, or using the plugins?

> 2. Feature restrictions (yours takes away streaming)

Streaming is fairly trivial; it could be added easily enough.

The only really big one is find_resource, which I'll concede is quite 
hard.  If there was at least a way to suggest such a hook while also 
providing a sane degredation, that would be ideal.  Then at least 
plugin/template developers would have something to shoot for.

> 3. What's optional (you consider WSGI optional, I want strings to be 
> optional)

This is kind of 1, since both interfaces can be used to implement the other.


-- 
Ian Bicking  |  ianb at colorstudy.com  |  http://blog.ianbicking.org


More information about the Web-SIG mailing list