[Web-SIG] Standardized template API
ben at groovie.org
Fri Feb 3 22:34:59 CET 2006
On Feb 3, 2006, at 11:57 AM, Phillip J. Eby wrote:
> 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.
What would be an example where PATH_INFO would not be empty?
> 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.
That would work fine for me, and is a rather trivial Routes tweak as
> 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.
Sure, again, I see no issue with that, though I'm sure many might
wonder why you'd want to. :)
> 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.
Wait, then how does the template engine know what 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.
Ok, so in my case, I'd pass the Myghty template engine the string
indicating the template I want rendered. Mainly because Myghty has
its own powerful compiling/caching system for templates, I wouldn't
want to try loading them myself and passing them as streams. But I
see how this affords that flexibility should you want this.
> 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.
Sweet, I read that twice and got my eyes to bug out. The interface is
flexible with WSGI, leaves lots of options open, I like... :)
> 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.
Ok, so.... I'm going to try and summarize to ensure that I have a
firm grasp on the proposal.
1) The template spec will use a WSGI call to ask the template engine
to return a WSGI application (iterable) of the rendered template
2) The spec shall declare 2 environ keys to be used:
2a) wti.source - either a stream or string which is the
template source (source as in code, or as in the name of the template
is up to the engine)
2b) wsgi.application_root - shall be used to access the original
SCRIPT_NAME if desired, ie, the SCRIPT_NAME of the application
calling the template engine
That's it. For a template language like Myghty, it already has a WSGI
handler that parses the template to render given the PATH_INFO, so
I'd merely sub-class its WSGIHandler to have it use wti.source as the
name of the template to render.
Now, there's a few things this doesn't touch at all, that the
TurboGears plug-in does address. Because wti.source is left open as
either a string, or a stream, and the meaning of said string could be
that its a string to be rendered as if it was a template, or it could
be as I'm used it here, as the string representing what template
Myghty should search for and render.
Though a small layer on top of the spec could handle it in whatever
way it preferred to, definitely a lot of flexibility involved. A
common question given the minimality of the spec as I'm summarizing
would be, "How do I tell my framework to pass a dict of variables
into the template so it can use them?"
This would probably be best done as adding a key to the environ. So I
propose in addition to the 2 keys:
2c) wti.vars - (optional) A dict representing variables you'd
like access to in the template should it provide ways to make them
To configure said template language implementing this spec would
differ slightly depending on what options the template language
needs. So each template language should include a small bit on what
the minimum configuration required to use it looks like. For Myghty
it might look like:
# setup the myghty engine
from myghty.wsgi import engine
myghtyengine = engine(template_root='/some/path/to/templates')
# render a template
environ['wti-source'] = template
environ['wti-vars'] = myvars
environ['wsgi.application_root'] = environ['SCRIPT_NAME']
environ['SCRIPT_NAME'] += environ['PATH_INFO']
environ['PATH_INFO'] = ''
return myghtyengine(environ, start_response)
So, the scope of this proposal is to cover the basics that the
template engine has access to, so that it can do what it will with
them. For those looking like a 'higher-level' interface like the
TurboGears template plug-in, it'd be very trivial to make a higher
abstraction based on this that can sort out differences in what
template languages "want" when it comes to configuration.
Anyways, hopefully this helps. Assuming I'm interpreting the WSGI as
template spec thing properly, I think it'll work great, and provide a
solid base for powerful template languages, as well as more minimal
ones (they can use a small WSGI wrapper).
More information about the Web-SIG