[Web-SIG] A trivial template API counter-proposal
ben at groovie.org
Sun Feb 5 20:47:09 CET 2006
On Feb 5, 2006, at 10:40 AM, Guido van Rossum wrote:
> I didn't see an output file in the proposed standard. All I saw was a
> WSGI interface. The output file is a figment of your implementation.
The WSGI interface indicates that the WSGI app will return its output
as an iterable. While WSGI was intended to unify the calling of these
frameworks, if we go with a WSGI style template call, it'd be trivial
to wrap it in something letting you do:
mytemplate = render_template('django', '/the/template.html', wsgi=False)
And in such a case, render_template will call the Django WSGI
interface with a basic WSGI environ, capture the headers, and return
a string of the rendered content. You'd be able to use the same
command with any of the template languages, and for the template
languages that do want to create their own response/request API's out
of the WSGI request, they still can.
> It is my strong preference that the standard API we are attempting to
> design here does *not* tie you strongly to WSGI or the generation of
> dynamic web content.
The fact is, that many template languages do provide abstractions of
objects present only in a web context though. Having an API that
fulfills this, like WSGI, lets you easily put a little function on
top like the render_template I showed that still does what you want.
> There's nothing wrong with having some things that can invoked from
> the template that set or add headers behind your back, if the template
> engine supports such a thing. But I think the API to let it do so
> might not be part of the standard, or it might be an optional part of
> the standard; I want to be able to use a templating engine in a
> non-web context and still use it (of course I won't be able to set
> headers then, but I'd assume this functionality is optional and I can
> just elect not to use it).
Of course, as I showed, its pretty trivial to use WSGI apps in such a
context. I can put together a more full fledged example as well, but
having WSGI under the hood avoids crippling the more full featured
template languages that do provide additional web context objects.
> This assumes wegiref though. I'd rather not make wsgiref a required
> part of the standard.
No need to, environ is basic dict, start_response is just a callable
(in non-wsgi, just supply a callable that eats the headers since you
won't use them), the response is an iterable, feel free to iterate
over it writing the content back out (imagine the template's rendered
response is huge, so you don't want it all in memory). Or maybe you
do want the full rendered output, just list() it. The freedom is left
up to you, and the template language still has the ability to do its
thing regardless of if you want to use it.
> No, I'd like to see the templating API and WSGI completely decoupled,
> except for an optional part where in the evaluation context passed
> into a template at render time, you pass in an object that lets the
> template manipulate headers etc. It would be fine if the latter used
> WSGI somehow. But there *must* be a standard way yo invoke the
> template engine (context in, string or stream out) without assuming
> it's an HTTP response.
WSGI at its heart is a very basic API. To come to an API for template
languages, that provides flexibility for the language, and options
for its output, we'll end up with an extremely similar API to WSGI I
> Please keep coming up with proposals and rationales for them. I will
> certainly admit that I haven't used a Python web framework in a while
> (not since I left Zope :-). But when I see Cheetah and Django and some
> competitors that were mentioned in responses to my blogs, a certain
> "Platonic ideal" of a templating engine emerges in my brain, and I'd
> like at least the API for that standardardized, if at all possible, so
> people writing frameworks can choose from the many templating engines
> available, and people with templating needs *outside* a web context
> can have the same selection.
I see no reason the template spec can't also provide for a unified
render call on top of the WSGI interface (for use in non-web
context). This would give you,
django = DjangoTemplate(**django_setup_args) # in case it needs a
template_root path, etc.
content, headers = django('/some/template.html', wsgi=False) #
content is an iterable
# web context
return django(environ, start_response)
# Or use Kid:
kidengine = KidTemplate(**kid_args)
content, headers = kidengine('some.template.kid', wsgi=False)
return kidengine(environ, start_response)
Or if people don't like relying on the object to determine if there's
a keyword with wsgi = False,
content, headers = kidengine.render('some.template.kid', wsgi=False)
return kidengine.wsgi(environ, start_response)
Regardless, everyone now has a uniform way to make a template
renderer, the template renderer can designate the options it should
take, and its output can be returned as an iterable for you, or it
can directly handle the WSGI call.
The polymorphic calling nature Phillip Eby describes could easily be
built in his framework by wrapping this process, but anyone will have
a rather uniform way to make a template engine instance, and use it.
Automated code could also be easily made to setup a few of these and
handle them accordingly (no need for it in the API).
How's that look?
More information about the Web-SIG