[Web-SIG] Standardized template API

Phillip J. Eby pje at telecommunity.com
Sat Feb 4 04:40:27 CET 2006


At 05:07 PM 2/3/2006 -0800, Ben Bangert wrote:
>On Feb 3, 2006, at 3:49 PM, Phillip J. Eby wrote:
>>I don't understand what you mean by "outside of Myghty" in this
>>context.  My suggestion was simply that would gain pluggability in
>>one main area: the implementation of compiling and serialization of
>>templates.  (i.e., the syntax/semantics of the templates used)
>
>I meant decoupled from the request to render the template. Since
>rendering the template may or may not require reloading/re-caching
>it, it seems like a process that the framework shouldn't have to
>consider.

My thoughts on caching were in the context of assuming the "manager" was 
part of the framework.  Frameworks that implement skins/layers and 
localizable resources have to do this, because template systems generally 
don't have any concept of skins or layers.  But it's seeming like we'll 
have to punt on this to some extent for now.


>>I'm still not understanding.  Since Myghty will be in control of
>>all the streams, it will have full ability to monitor changes etc.
>>The only thing that's different under the embedding scheme is that
>>1: it would support multiple formats for the actual templates, and
>>2: it would return WSGI apps that frontend access to an individual
>>template.
>
>Yes, that is useful functionality. Would the call to the WSGI app
>that renders the template also trigger something that ensures its re- 
>compiled if it needs to be?

Sure.  You can just do something like:

def resource_returned_by_manager(environ, start_response):
     if needs_recompiling(actual_resource):
         recompile(actual_resource)
     return actual_resource(environ, start_response)

That is, the manager doesn't have to return the resource returned by the 
compiler; it can wrap a trivial reloader middleware around it and return that.

Of course, the more I look at this, the more I realize that your idea of 
just putting the entire "manager" interface in one WSGI call might make 
good sense too.  Because unless the "publisher" is going to hang on to the 
returned app, you might as well just integrate this stuff at the manager level.

The problem for me is, I was hoping we would end up defining a 
manager->compiler interface and a publisher->resource interface rather than 
a publisher->manager one.  Then again, maybe we should define both, and let 
people plug things in where they can.  It would provide a path for 
gradually evolving to the place where everything's pluggable.


>It usually is, which is part of the reason it might be nice to have
>it decoupled so the most robust compiler/loader can be used, if thats
>possible. Such template agnosticism might come at a very hefty
>workload cost, as Mike mentioned about how much time it'd take to
>splice this functionality into separate parts.

I'm leaning more now towards defining a publisher->manager and 
publisher->resource interface pair based on WSGI as making the most sense 
for the present.  A manager->compiler interface would be nice too, but 
perhaps not strictly necessary for the original use cases that prompted 
this discussion.


>>I'm seeing now that the key problem with my view of the situation
>>is that I've been assuming *frameworks* have control over where and
>>how templates are stored, and considering the template systems to
>>be just that - implementation of the template itself.
>
>Ah, yes. That explains a lot. In my experience with various template
>systems, the directory structure of the template root can also
>influence the rendering of the template. In Myghty this structure is
>used for automatic inheritance, Cheetah, Kid, Django templates, and
>others all include the ability to "extend" existing templates within
>a template. This means they all need to resolve the included
>template, and cache it. That reason is why all of them already have
>their own caching/compiling stuff integrated.

In my view, this is a bit suboptimal in the long haul, because there's all 
this duplicated code for managing files, and probably little -- if any -- 
of it works with eggs, or templates in a database (e.g. ZODB), etc.  This 
is part of why my mental model didn't really consider much about template 
systems having their own "manager" parts - the idea seems manifestly 
unworkable if you need to do things like what Zope 3 supports.

Of course, my long-term ambition here would be that we get to a place where 
you can do skinning and localization with templates and other resources, 
all using a Python-wide standard for how you identify and deploy these 
resources.  But that's out of scope for the current interface discussions, 
alas.

It might be nice, though, to put together a session at PyCon to do some 
brainstorming on templates, embedding, and deployment to see if there are 
currently any easily-reached opportunities.


>>So, on a given request, the publisher asks the manager for a
>>resource by saying what template it wants.  The manager does
>>whatever it needs to do, possibly invoking the compiler if it needs
>>to.  The publisher then makes a WSGI call on the resource to render
>>it.
>
>Where along these steps, are the variables passed into the template?

When the publisher makes the WSGI call, it would add a 'params' key and/or 
a 'published_object' key, depending on whether the publisher is an object 
publisher or does parameters or both.  I can imagine that Zope, for 
example, might do both, drawing on its request parsing to do parameters.  A 
TurboGears or other controller-type framework that uses templates for 
postprocessing would put the variables in 'params'.  These names are 
hypothetical and subject to getting a firm spec, of course.


>Once the template is compiled/cached, in addition to calling it, I
>need to pass it variables that it will be using. Are all templates
>going to be expected to pull variables they should see from the environ?

Yeah, from the 'params' key or 'published_object' or both.


>>I was at first assuming that "framework" meant the publisher and
>>manager, and "engine" was the compiler and resource.  Then to
>>explain better I split compiler and resource, but now I see that I
>>should've split (conceptually) the publisher and manager.
>
>Ok, so if I'm using this in my web application. Somehow, I'm going to
>need to check to see if the template has been compiled/cached, then I
>have to go and call the WSGI app? With all these compiled/cached
>templates that've been used, what's holding onto all those many, many
>WSGI apps that've been created? Some of my web applications have
>upwards of thousands of templates, is there going to be thousands of
>WSGI apps in memory waiting to be called? I'm guessing/hoping I
>missed something and this isn't the case.

Nah, the issue here was that I envisioned the division differently than 
Ian; my concern about being able to cache was because I envisioned the 
"manager" being on the framework side of the line; ergo, the framework 
needed caching.  If the interface is strictly between the publisher and the 
manager, then you could potentially just do it all with a single WSGI call, 
in which the manager pulls the template identifier from the environ.

But it seems a little ugly to me to cram another key into environ to tell 
the manager what template to use, when you could just have a 
'get(template_id)' call that gets you the WSGI app to use.  It also makes 
the objects' responsibilities a little more clearly defined, since a WSGI 
app in the general case doesn't take a template_id parameter, if you see 
what I mean.


>Since templates in a bunch of these template languages will
>frequently include other templates, all the 'resource' instances will
>need access to call back to the 'publisher' so that they can do what

To the manager actually, since the manager is responsible for id->template 
lookups.

>they need to for the template to be rendered and included. Some
>template systems go farther still than basic including of another
>template and start extending other templates. Kid will have one
>template override parts of templates it "inherits" from. Myghty will
>have parent templates that will insert their "child" templates in
>various fashions. Cheetah and Django also do things like this.

ZPT has macros, peak.web has DOMlets and layouts, etc., etc.  Lots of 
variety to choose from.  :)


>All these systems will need ways to tie back into the manager so that
>they're all loaded, compiled, cached when needed, and that individual
>parts of the whole get reloaded when necessary without reloading
>everything.
>
>If there's a way to separate out this very convoluted process (that
>isn't necessarily the same for each system), it'd be very compelling
>I think. Especially since solid code to handle many of the problems
>that can occur under load when doing all this reloading/caching/etc
>is not easy stuff.

I'm beginning to think that this actually ties in pretty closely with the 
deployment issues, in the sense that you may need basically multiple 
"sources" of template/resource implementations, especially if you're 
supporting skins or localization.  It's almost like you need a registry of 
template ids to ways to get them, that have been registered via plugins.

Of course, in the use cases you guys are talking about, you presume that 
there's just a "template root", which is way too simple for the kinds of 
stuff Zope 3 and peak.web want to do.  Both have the notion of "skins", 
which are composed of "layers".  A layer can provide alternate versions of 
any given template, and layers can be combined to form skins.  There's no 
particular requirement that these layers have any filesystem relationships, 
and in the Zope case they may be in ZODB in any case, not the 
filesystem.  In PEAK's case, the layers can live in different eggs, and I 
suspect Zope will want to allow the same as they increase their support for 
eggs.

Anyway, that's why I think that if we can come up with a "bottom up" way to 
provide template sources, then we can have a manager that's just a thin 
layer over these providers.  Stuff that's supplied by eggs, for example, 
will probably be precompiled and won't need to be refreshed.  Stuff in ZODB 
has its own caching.  So, to a certain extent, I think the ultimate future 
will be that our "manager" will just be something that figures out what 
backend is supplying the stuff and hand off the handling to it.  We'll have 
some "file" managers, "egg" managers, "ZODB" managers, etc. plugged in via 
entry points or some such.

Of course, this is all "future" stuff.  I had hoped we were closer to being 
able to do it, though, as I'd been meaning to build some of it for 
peak.web, and didn't want to end up in the position of appearing to say, 
"hey, everybody should do this stuff I did for peak.web".  :)  Instead, I'd 
be saying, "peak.web now supports the new WSGI embedding and resource 
deployment specs".  :)


>I think many of us are actually talking about two different
>proposals. The proposal for standardized templating you're talking to
>sounds like WSGI for template languages. That is, it pushes common
>parts many template languages have, into a re-usable layer. I'm not
>sure such a thing is possible, its definitely quite ambitious, and I
>look forward to the more clearly defined spec you put out.

Well, I'm realizing now that the more ambitious bits are harder because 
there's more that's actually been done out there in the template engines 
than I thought.  If there were less, more standardization would've been an 
obvious move forward and more doable now.


>The proposal many of us were looking for (I think), was merely a more
>unified way of calling a template. That is, we want a standard
>'publisher' interface, so that we can call someengine.render('some/ 
>template.myt', myvars) and its rendered. The TurboGears template plug- in 
>thing describes such a thing, but it could use some more work. The
>way I interpreted your proposal originally also set things up in such
>a way that there was a base system for configuring a template engine,
>then you just call the app and put your vars in environ.
>
>As the more ambitious one is likely to take significantly more effort
>from everyone involved (assuming it'll work), can we unify a setup/ call 
>structure first? I see no reason it won't be compatible in the
>end with standardizing the "internals" of the template languages as
>well.

I concur.  What I propose right now is that we have a "manager" interface 
that gets asked for a template by a name or ID, and returns a WSGI app 
object.  Calls to that object can then include 'params' and/or 
'published_object'.  (Exact spelling TBD.)

I don't think this interface should suggest/recommend an addressing scheme, 
nor a plugin scheme.  That is, I don't think it should include specifiers 
for entry points or anything like that.  Instead, to do the TG/B style of 
plugins, you should just have a manager that figures out what template 
engine/plugin to use.  The identifier can and should be opaque.

By that I mean, you could have a manager object that looks for a prefix 
like "kid:" at the beginning of the ID and then looks up an entry point to 
forward to another manager.  But that would just be one way of implementing 
the spec, not something required by the spec.  The reason is that this then 
leaves open both the possibility of developing generic and/or polymorphic 
"manager" objects.

The big open question is how to create and configure a manager object, 
since different managers will have different needs.  For example, peak.web 
uses module-relative paths in the default layer of the default skin; it has 
no "root" directory.  Each layer can also have its own directory, and I 
believe Zope 3 does the same.



More information about the Web-SIG mailing list