Buffet has been both a success and a failure. It's been a success in
that it's encouraged some semblance of an API that's been widely
adopted. It's been a failure in that it fails to adequately define key
elements of that API. The current API defines what methods a template
engine adapter will provide and what arguments that adapter will accept.
At the same time it fails to adequately describe *what* will be
contained in those arguments and *when* they will be provided.
I started noticing issues with the Buffet API when I attempted to
support both TurboGears and Pylons in my Breve template engine. Both
frameworks take their own route at several key places. Some of these
can be attributed to bugs in the frameworks or their Buffet
implementations and some simply to oversight in the Buffet
specification.
1. Configuration data
======================
Configuration data can be broken into two main sections: persistent
configuration (to be provided at engine instantiation) and rendering
configuration (to be provided at template rendering).
Failures of TurboGears WRT configuration
----------------------------------------
a) TurboGears currently instantiates the template engine prior to
parsing its own configuration file. This means that things like a
template root directory aren't known and must be passed later
(TurboGears passes it at render time). This is clearly inefficient (it
requires doing path manipulation on every rendering), but worse,
conflicts with Pylons which does in fact pass this information at
instantiation time.
b) TurboGears passes in a CherryPy config object. This is suboptimal
for two reasons: 1) it isn't an iterable. This means the adapter (which
is separate from the engine proper) must explicitly request
configuration data. This means that both the engine as well as the
adapter must maintain a list of possible parameters. This violates DRY
and imposes needless special case code on the adapter. 2) This is
clearly CherryPy-centric and makes it more difficult for non-CherryPy
based frameworks to follow suite. 3) Examples on the Buffet site
suggest that it should be a Python dictionary.
Failures of Pylons WRT configuration
------------------------------------
a) It fails to follow TurboGears' lead in the matter, right or wrong as
it may be.
IMO, the Pylons method of passing in a dictionary is far superior and
more flexible than the TurboGears method of passing in a CherryPy config
object and falls in line with the Buffet examples (e.g. BuffetString).
What should be done
-------------------
Any *persistent* (e.g. read from a framework's .ini or .cfg file)
configuration should be passed at engine instantiation *as a Python
dictionary*. Further, this dictionary should *not* contain the entire
framework configuration, rather just the items relevant to the template
engine. Further, any prefixes should be probably be stripped prior to
passing them in (i.e. "genshi.encoding" would become just "encoding").
It isn't critical that prefixes be removed, but it needs to be decided
one way or the other what format the arguments are to be expected in.
Remove the prefixes or don't, but most certainly don't leave it up to
the frameworks to guess at it.
Any *rendering parameters* (e.g. format='html') should be passed to the
render() method. For the most part this does happen now, except that
some presumably persistent data is mixed in with it.
Dotted path notation
====================
This now seems like a bad idea. It was thought to be needed for Kid but
I'm not certain this is actually true. Further, having a requirement
fitted to a single template engine is a bad idea (and now that Kid is
apparently going away in favor of Genshi, seems doubly bad). Frankly I
think this might actually be a place where a specification doesn't
matter. TurboGears doesn't enforce using the dotted notation nor does
Pylons so it seems pretty superfluous. As far as I'm concerned, the
format for this argument could simply be "a string that is *meaningful
to the underlying engine*, whether it be a dotted Python module path, a
Unix filesystem path or even a URI". There is no portability to be
gained in specifying the format of this argument, but lots of
flexibility to be lost.
Here's an outline of the changes I'm proposing provided as annotation to
the existing API (derived from buffetstring):
class TemplatePlugin(object):
# all template plugins need to define a default file extension
extension = "tmpl"
def __init__(self, **config):
"""
config == dict() of persistent configuration settings, e.g.
settings derived from a .ini or .cfg file
"""
self.config = config
def render(self, template, info, **options):
"""
info == dict of variables to stick into the template namespace
template == string that is meaningful to underlying engine as a
template selector (e.g. Unix path, dotted module path, URI, etc).
There is no enforced nor suggested format.
options == dict of render-time settings (e.g. "format", "fragment")
"""
return rendered_template
Notable changes:
The argument extra_vars_func seems superfluous as TurboGears provides no
way at runtime to modify it (that I'm aware of) and what it typically
provides should most likely be provided elsewhere. Simply pass
persistent data to __init__() and render-time data to render() and I no
longer see a need for extra_vars_func().
"template" argument isn't optional. Unless someone has a use-case for
having it optional (which seems rather inexplicable to me), I'd think
the API is simpler with it as a required argument.
Various render-time configuration (e.g. format and fragment) are passed
as keyword arguments. There may be other options that are
engine-specific so this allows for maximum flexibility. That being the
case, there is no reason to treat the other render-time arguments
"format" and "fragment" (that may or not be meaningful to all engines)
in a different fashion. It's simpler and more consistent to simply pass
all render-time arguments as keyword arguments.
AFAICT, there's no need to spec additional methods that are only used
internally by the module anyway (i.e. load_template). The spec should
only cover the external API.
Previously it was discussed that there should be a "template finder" or
loader. I think this is also superfluous since it's quite simple (and
far more efficient) to simply define a "template root" and pass it as a
config option and let the engine interpret that as it may. If an engine
wants to do something fancier (like Django's path searching), that
should be done by the adapter (perhaps relative to the template.root),
but not really cared about by the API. I think Ian suggested that this
might be used to do stuff like load templates from a database or some
other unknown piece of storage, but this opens a can of worms. If this
is really desired, simply set the document.root to be a database URI and
let the adapter figure out what to do with it. I'm not certain there's
a clean (or threadsafe) way to pass in an existing database connection
object to the adapter anyway (but I'm willing to be corrected on this
point).
All feedback welcome.
Regards,
Cliff
1) Existing bugs in current implementations that should be fixed
regardless (e.g. TurboGears' passing in a CherryPy config object and not
having parsed its config file at engine instantiation time). This needs
to be fixed regardless and will most likely represent a breaking change
no matter what.
a) TurboGears 2.0 will undoubtedly break lots of stuff anyway, so this
seems a good time to break other things.
b) The Pylons implementation is also currently broken (e.g. fails to
pass through things like the "format" argument to the render() method).
2) For engine authors, these changes are fairly trivial to implement
(I'd expect an afternoon of work at most), so most of the problem will
come down to packaging/versioning issues. Perhaps a new entry_point?
Regards,
Cliff
All your caveats make me still think a loader would be useful ;) For
instance, I think it's strange if Django internally implements path
searching, and so the layout for templates would presumably be entirely
different for Django than another templating language (because you'd be
referring to path names that were actually under a set of search paths
somehow). Plus how do you deal with a set of search paths that aren't
under any particular root?
The loader doesn't add much complexity to engines, except that what it
does is deep in the engine and hard to handle otherwise. It's up to the
loader to do things like get database connections, handle thread safety,
etc. Probably all it should do is return text. (I think I had it doing
more than that, but that might be bad.) This all is not that unlike
pkg_resources resource stuff which has a similar scope.
--
Ian Bicking | ia...@colorstudy.com | http://blog.ianbicking.org
> All your caveats make me still think a loader would be useful ;) For
> instance, I think it's strange if Django internally implements path
> searching, and so the layout for templates would presumably be entirely
> different for Django than another templating language (because you'd be
> referring to path names that were actually under a set of search paths
> somehow). Plus how do you deal with a set of search paths that aren't
> under any particular root?
Frankly I'm not fond of the Django search path idea (I think it violates
the principle of least surprise, not to mention seeming a bit...
inefficient), I was just using it as an example of what odd things
engines might want to do and pointing out that this could be done either
within the Buffet adapter or even within the engine itself (that is,
without defining a public API in Buffet for supporting such things).
> The loader doesn't add much complexity to engines, except that what it
> does is deep in the engine and hard to handle otherwise. It's up to the
> loader to do things like get database connections, handle thread safety,
> etc. Probably all it should do is return text. (I think I had it doing
> more than that, but that might be bad.) This all is not that unlike
> pkg_resources resource stuff which has a similar scope.
The problem I see (but perhaps it's clearer to more clever people), is
how to provide adequate application-specific information without getting
glue all over everything. I think pulling templates from a database is
a perfect example (if we can solve that one, then everything else should
be relatively simple). Clearly the framework shouldn't pass an actual
database connection, rather it should pass a connection string and let
the template engine establish its own persistent connection using
whatever means it needs to. To me this suggests passing the connection
URI as an argument to __init__ since establishing a connection on each
load/render is going to be highly inefficient.
This sums up part of my feelings on what's currently wrong with the
Buffet API: it needs to be a bit more transparent. There's no reason
why a particular engine couldn't accept multiple template roots (e.g.
one for filesystem templates and a URI for database ones) or multiple
arguments for "format" (e.g. html and tidy), but the current API
currently limits an engine to what we've thought of to date or forces
workarounds. Extending the API isn't a solution. We need to simplify
it. I much prefer the WSGI style where we keep the method signatures
extremely simple and let different layers extract what they need from
the provided data.
This doesn't directly discount your desire for a loader, but I'm having
a difficult time seeing what benefit it provides over simply passing
appropriate information at instantiation... I'm just not seeing the
use-case (probably old age inhibiting my imagination). If you feel up
to it, perhaps you could present a concrete example (utilizing an
imaginary engine) that somehow leverages a loader being called prior to
rendering to help me out. I know, I ask for a lot ;-)
Regards,
Cliff
On Tue, 2007-01-30 at 13:33 -0800, Cliff Wells wrote:
> This doesn't directly discount your desire for a loader, but I'm having
> a difficult time seeing what benefit it provides over simply passing
> appropriate information at instantiation... I'm just not seeing the
> use-case (probably old age inhibiting my imagination). If you feel up
> to it, perhaps you could present a concrete example (utilizing an
> imaginary engine) that somehow leverages a loader being called prior to
> rendering to help me out. I know, I ask for a lot ;-)
To clarify my question, what's the advantage of:
framework calls buffet.__init__
framework calls buffet.load_template
framework calls buffet.render
over:
framework calls buffet.__init__
framework calls buffet.render
buffet.render calls buffet.load_template
It seems to me they accomplish the same goal, but the first requires
additional specifications in the public API (opening the door to more
misinterpretation in the frameworks).
Regards,
Cliff
Christian very tardily replied:
Sorry for not giving any input on this sooner. Life offline has been
quite consuming lately.
> Buffet has been both a success and a failure. It's been a success in
> that it's encouraged some semblance of an API that's been widely
> adopted. It's been a failure in that it fails to adequately define key
> elements of that API. The current API defines what methods a template
> engine adapter will provide and what arguments that adapter will accept.
> At the same time it fails to adequately describe *what* will be
> contained in those arguments and *when* they will be provided.
I agree. The API developed quickly and was practically useful from
the get go. Perhaps some of the deficiencies in the API are due to
its ad-hoc creation and quick adoption. Kevin Dangoor basically came
up with dict-passing-to-template idea for Turbogears, I thought that
would be a useful feature for any CherryPy based app, thus the Buffet
filter, and then Kevin contacted me about sharing plugin code to save
people some hassle. There were a few initial emails about the API,
and then it was born.
The flurry of posts to the WEB-SIG about the API were interesting but
mostly fruitless in the end. I think your suggestions are the first
attempt to tackle a key deficiency in the API in about a year now.
> I started noticing issues with the Buffet API when I attempted to
> support both TurboGears and Pylons in my Breve template engine. Both
> frameworks take their own route at several key places. Some of these
> can be attributed to bugs in the frameworks or their Buffet
> implementations and some simply to oversight in the Buffet
> specification.
So it seems like the deficiencies were probably noticed earlier, but
rather than working them out by adjusting the template API, they were
worked around in code.
> 1. Configuration data
> ======================
> Configuration data can be broken into two main sections: persistent
> configuration (to be provided at engine instantiation) and rendering
> configuration (to be provided at template rendering).
I think that is a logical distinction.
> Failures of TurboGears WRT configuration
> ----------------------------------------
> a) TurboGears currently instantiates the template engine prior to
> parsing its own configuration file. This means that things like a
> template root directory aren't known and must be passed later
> (TurboGears passes it at render time). This is clearly inefficient (it
> requires doing path manipulation on every rendering), but worse,
> conflicts with Pylons which does in fact pass this information at
> instantiation time.
That does seem to be a strange approach. It does work around the
problem of initialization-time/run-time configuration (making it all
run-time essentially) but creates problems for folks like you trying
to make a plugin that works correctly across frameworks (the whole
point of the API).
> b) TurboGears passes in a CherryPy config object. This is suboptimal
> for two reasons: 1) it isn't an iterable. This means the adapter (which
> is separate from the engine proper) must explicitly request
> configuration data. This means that both the engine as well as the
> adapter must maintain a list of possible parameters. This violates DRY
> and imposes needless special case code on the adapter. 2) This is
> clearly CherryPy-centric and makes it more difficult for non-CherryPy
> based frameworks to follow suite. 3) Examples on the Buffet site
> suggest that it should be a Python dictionary.
Yeah, that doesn't seem to be right. It should just be a dict, IMO.
It is easy enough to get to the underlying dict in the CherryPy config
object anyhow (cherrypy.config.configs[path] in 2.2.x, IIRC).
> Failures of Pylons WRT configuration
> ------------------------------------
> a) It fails to follow TurboGears' lead in the matter, right or wrong as
> it may be.
The problem of inertia is going to be the biggest one in getting this
thing turned around, I think. Sooner sure is better than later,
before Pylons and TG diverge further with respect to the template API.
> IMO, the Pylons method of passing in a dictionary is far superior and
> more flexible than the TurboGears method of passing in a CherryPy config
> object and falls in line with the Buffet examples (e.g. BuffetString).
I agree.
> What should be done
> -------------------
> Any *persistent* (e.g. read from a framework's .ini or .cfg file)
> configuration should be passed at engine instantiation *as a Python
> dictionary*. Further, this dictionary should *not* contain the entire
> framework configuration, rather just the items relevant to the template
> engine. Further, any prefixes should be probably be stripped prior to
> passing them in (i.e. "genshi.encoding" would become just "encoding").
> It isn't critical that prefixes be removed, but it needs to be decided
> one way or the other what format the arguments are to be expected in.
> Remove the prefixes or don't, but most certainly don't leave it up to
> the frameworks to guess at it.
This sounds reasonable. Frameworks should be able to use whatever
config format they want but the keys passed to the engines should make
sense as engine parameter names.
> Any *rendering parameters* (e.g. format='html') should be passed to the
> render() method. For the most part this does happen now, except that
> some presumably persistent data is mixed in with it.
Sounds good.
> Dotted path notation
> ====================
> This now seems like a bad idea. It was thought to be needed for Kid but
> I'm not certain this is actually true. Further, having a requirement
> fitted to a single template engine is a bad idea (and now that Kid is
> apparently going away in favor of Genshi, seems doubly bad). Frankly I
> think this might actually be a place where a specification doesn't
> matter. TurboGears doesn't enforce using the dotted notation nor does
> Pylons so it seems pretty superfluous. As far as I'm concerned, the
> format for this argument could simply be "a string that is *meaningful
> to the underlying engine*, whether it be a dotted Python module path, a
> Unix filesystem path or even a URI". There is no portability to be
> gained in specifying the format of this argument, but lots of
> flexibility to be lost.
Yeah, the dotted-path notation was certainly just a consolation that
Turbogears was the biggest consumer of the API at the time it was put
together and "required" that format. I like the "meaningful string"
idea, but one nice thing about settling on a standard way of
representing the location of a template is not having anything
engine-specific bubbling up to the top. If Kid does require a
dotted-path, and I decided to switch to Foo which requires a standard
path representation, it sucks to have to go through however many
modules and lines of code I have that reference template names and
change them to support the different path format.
>
> Here's an outline of the changes I'm proposing provided as annotation to
> the existing API (derived from buffetstring):
>
> class TemplatePlugin(object):
> # all template plugins need to define a default file extension
> extension = "tmpl"
>
> def __init__(self, **config):
> """
> config == dict() of persistent configuration settings, e.g.
> settings derived from a .ini or .cfg file
> """
> self.config = config
>
> def render(self, template, info, **options):
> """
> info == dict of variables to stick into the template namespace
> template == string that is meaningful to underlying engine as a
> template selector (e.g. Unix path, dotted module path, URI, etc).
> There is no enforced nor suggested format.
> options == dict of render-time settings (e.g. "format", "fragment")
> """
> return rendered_template
I like it, except for my previously stated reservation about the
"meaningful string" idea.
> Notable changes:
>
> The argument extra_vars_func seems superfluous as TurboGears provides no
> way at runtime to modify it (that I'm aware of) and what it typically
> provides should most likely be provided elsewhere. Simply pass
> persistent data to __init__() and render-time data to render() and I no
> longer see a need for extra_vars_func().
The idea with this was for sticking framework-specific vars into the
template namespace. For instance, I use it in the Buffet filter to
always make the cherrypy object available in the template namespace.
> "template" argument isn't optional. Unless someone has a use-case for
> having it optional (which seems rather inexplicable to me), I'd think
> the API is simpler with it as a required argument.
I'm interested in hearing about a templateless-templating system as well :-)
> Various render-time configuration (e.g. format and fragment) are passed
> as keyword arguments. There may be other options that are
> engine-specific so this allows for maximum flexibility. That being the
> case, there is no reason to treat the other render-time arguments
> "format" and "fragment" (that may or not be meaningful to all engines)
> in a different fashion. It's simpler and more consistent to simply pass
> all render-time arguments as keyword arguments.
That makes sense to an extent, as long as this doesn't lead to
bubbling-up of engine-specific details into code.
> AFAICT, there's no need to spec additional methods that are only used
> internally by the module anyway (i.e. load_template). The spec should
> only cover the external API.
I agree.
As an aside, one thing that I have always found curious is that the
Buffet name stuck with the template API. It is quite a minor
implementation and only a tiny bit of code - perhaps calling it the
Turbogears template API would attach it too closely to that particular
framework. Anywho...
Thanks for bringing this stuff up for discussion. Perhaps the best
thing to do at this point is to get folks from the two biggest
consumers of the API (Turbgears and Pylons) to comment on this.
I know that in TG-land Elvelind Grandlin is working on some
template-related improvements, but I don't know how much of a
departure the work is from the current API. Elvelind, if you are out
there, could you comment?
The Pylons code seems to be closest to the spirit of the proposed
changes, so I am not sure that there is much to be done there, but it
would still be good to get some input.
But I guess that is what you tried to do a month ago when you wrote
the initial email in this thread...
Perhaps we can find some time to meet up and toss ideas around at PyCon?
Christian
http://www.dowski.com
> Christian very tardily replied:
> Sorry for not giving any input on this sooner. Life offline has been
> quite consuming lately.
Yeah, I know the feeling. It's only inconvenient in that everyone's
busy times don't line up ;-)
> I agree. The API developed quickly and was practically useful from
> the get go. Perhaps some of the deficiencies in the API are due to
> its ad-hoc creation and quick adoption. Kevin Dangoor basically came
> up with dict-passing-to-template idea for Turbogears, I thought that
> would be a useful feature for any CherryPy based app, thus the Buffet
> filter, and then Kevin contacted me about sharing plugin code to save
> people some hassle. There were a few initial emails about the API,
> and then it was born.
Yep. I was there and failed to help prevent this as well. 20/20
hindsight of course.
> > I started noticing issues with the Buffet API when I attempted to
> > support both TurboGears and Pylons in my Breve template engine. Both
> > frameworks take their own route at several key places. Some of these
> > can be attributed to bugs in the frameworks or their Buffet
> > implementations and some simply to oversight in the Buffet
> > specification.
>
> So it seems like the deficiencies were probably noticed earlier, but
> rather than working them out by adjusting the template API, they were
> worked around in code.
That has certainly been the case for me.
> > Failures of TurboGears WRT configuration
> > ----------------------------------------
> > a) TurboGears currently instantiates the template engine prior to
> > parsing its own configuration file. This means that things like a
> > template root directory aren't known and must be passed later
> > (TurboGears passes it at render time). This is clearly inefficient (it
> > requires doing path manipulation on every rendering), but worse,
> > conflicts with Pylons which does in fact pass this information at
> > instantiation time.
>
> That does seem to be a strange approach. It does work around the
> problem of initialization-time/run-time configuration (making it all
> run-time essentially) but creates problems for folks like you trying
> to make a plugin that works correctly across frameworks (the whole
> point of the API).
It's actually due to a bug in TurboGears that I've been having a
difficult time getting anyone to care about ("works for me" syndrome).
TurboGears initializes the template engines prior to fully parsing the
config file. To overcome this, they've hacked in a bit of
engine-specific code (i.e. they read out a few specific kid and genshi
settings) and pass those in.
> > b) TurboGears passes in a CherryPy config object. This is suboptimal
> > for two reasons: 1) it isn't an iterable. This means the adapter (which
> > is separate from the engine proper) must explicitly request
> > configuration data. This means that both the engine as well as the
> > adapter must maintain a list of possible parameters. This violates DRY
> > and imposes needless special case code on the adapter. 2) This is
> > clearly CherryPy-centric and makes it more difficult for non-CherryPy
> > based frameworks to follow suite. 3) Examples on the Buffet site
> > suggest that it should be a Python dictionary.
>
> Yeah, that doesn't seem to be right. It should just be a dict, IMO.
> It is easy enough to get to the underlying dict in the CherryPy config
> object anyhow (cherrypy.config.configs[path] in 2.2.x, IIRC).
I understand that the CP3 config object presents the full set of dict
methods, but that pushes the solution out to TG 2.0 (i.e maybe sometime
in 2008 <wink>). I think this could be addressed in TG 1.x by simply
extending the config object with a couple methods (keys, items,
values).
> > Failures of Pylons WRT configuration
> > ------------------------------------
> > a) It fails to follow TurboGears' lead in the matter, right or wrong as
> > it may be.
>
> The problem of inertia is going to be the biggest one in getting this
> thing turned around, I think. Sooner sure is better than later,
> before Pylons and TG diverge further with respect to the template API.
Agreed wholeheartedly.
> > Dotted path notation
> > ====================
> > This now seems like a bad idea. It was thought to be needed for Kid but
> > I'm not certain this is actually true. Further, having a requirement
> > fitted to a single template engine is a bad idea (and now that Kid is
> > apparently going away in favor of Genshi, seems doubly bad). Frankly I
> > think this might actually be a place where a specification doesn't
> > matter. TurboGears doesn't enforce using the dotted notation nor does
> > Pylons so it seems pretty superfluous. As far as I'm concerned, the
> > format for this argument could simply be "a string that is *meaningful
> > to the underlying engine*, whether it be a dotted Python module path, a
> > Unix filesystem path or even a URI". There is no portability to be
> > gained in specifying the format of this argument, but lots of
> > flexibility to be lost.
>
> Yeah, the dotted-path notation was certainly just a consolation that
> Turbogears was the biggest consumer of the API at the time it was put
> together and "required" that format. I like the "meaningful string"
> idea, but one nice thing about settling on a standard way of
> representing the location of a template is not having anything
> engine-specific bubbling up to the top. If Kid does require a
> dotted-path, and I decided to switch to Foo which requires a standard
> path representation, it sucks to have to go through however many
> modules and lines of code I have that reference template names and
> change them to support the different path format.
Well there's a very specific issue that dotted notation introduces: dot
is a valid character in paths on every OS I'm aware of. So for instance
on my shared hosting boxes, a site's home directory is of the
form /var/www/virtual/domain.tld/. The naive template_path.split('.')
approach fails here and a correct solution isn't obvious (nor would it
be efficient). Also it's been suggested that the filesystem might not
be the only place a template could be loaded from (databases are an
obvious option). If we had to settle on a format, I'd suggest that a
URI would provide the maximum flexibility.
Also, I think that changing engines would require enough work that
adding changing the path format would be a relatively minor nit at that
point.
Okay. But if we have it, let's define what it should/shouldn't do (i.e.
TG should *not* be passing configuration data in via that method).
> > Various render-time configuration (e.g. format and fragment) are passed
> > as keyword arguments. There may be other options that are
> > engine-specific so this allows for maximum flexibility. That being the
> > case, there is no reason to treat the other render-time arguments
> > "format" and "fragment" (that may or not be meaningful to all engines)
> > in a different fashion. It's simpler and more consistent to simply pass
> > all render-time arguments as keyword arguments.
>
> That makes sense to an extent, as long as this doesn't lead to
> bubbling-up of engine-specific details into code.
Part of the issue currently is that there *isn't* a good way to pass
engine-specific details in from the frameworks. That is, some of the
power/flexibility of the underlying engine is left untapped because it
wasn't thought of at the time the API was defined. I think there are
two potential evils here and letting the framework user tap into some
engine details is the lesser of the two.
> As an aside, one thing that I have always found curious is that the
> Buffet name stuck with the template API. It is quite a minor
> implementation and only a tiny bit of code - perhaps calling it the
> Turbogears template API would attach it too closely to that particular
> framework. Anywho...
Well, it's good to attach names to concepts if you want to talk about
them. "Buffet" clearly won by being good enough ;-)
> Thanks for bringing this stuff up for discussion. Perhaps the best
> thing to do at this point is to get folks from the two biggest
> consumers of the API (Turbgears and Pylons) to comment on this.
Agreed. I've talked to Ben Bangert and Ian Bicking on #pylons about
this and they've got some additional thoughts on the matter. The most
difficult group to drag in would appear to be the TG devs (I think
they've got a lot on their plates in major overhauls for 1.1 and 2.0 and
this is just too far below their radar). My idea is to tackle Kevin
Dangoor on the matter. Even though he's not the TG lead anymore he's
still involved and has enough sway to help push things a bit.
> I know that in TG-land Elvelind Grandlin is working on some
> template-related improvements, but I don't know how much of a
> departure the work is from the current API. Elvelind, if you are out
> there, could you comment?
I chatted with Elvelind on IRC a while back and I seem to recall he was
thinking of a WSGI-oriented approach, so I'm not sure that his ideas
would be applicable to Buffet.
> The Pylons code seems to be closest to the spirit of the proposed
> changes, so I am not sure that there is much to be done there, but it
> would still be good to get some input.
Yep.
> But I guess that is what you tried to do a month ago when you wrote
> the initial email in this thread...
>
> Perhaps we can find some time to meet up and toss ideas around at PyCon?
Unfortunately I won't be there. But I'm working on getting the right
people to talk to each other (and trying to get at least a minimal set
of patches into TG to solve some of the bigger issues and make way for a
revision in the API).
Regards,
Cliff
> Yeah, the dotted-path notation was certainly just a consolation that
> Turbogears was the biggest consumer of the API at the time it was put
> together and "required" that format. I like the "meaningful string"
> idea, but one nice thing about settling on a standard way of
> representing the location of a template is not having anything
> engine-specific bubbling up to the top. If Kid does require a
> dotted-path, and I decided to switch to Foo which requires a standard
> path representation, it sucks to have to go through however many
> modules and lines of code I have that reference template names and
> change them to support the different path format.
One more point on this: if the configuration issues were resolved, it
would be possible to add "myengine.dotted_paths = true" which would
allow adapters to provide a workaround for this if people didn't want to
be bothered with it (and it didn't affect their particular deployment).
In fact it seems somewhat arguable that the format of the template path
is in fact a deployment consideration and should therefore "bubble up"
from the framework's config file.
On this note, Ian has also suggested that we allow for a custom loader
function to be passed to the adapter which would certainly affect how
the template path might be specified.
As an aside, I've had two requests to-date for a similar feature in
Breve (from people who want a Django-like template search path vs a
static template root), so I think it's worth considering a pluggable
loader.
Regards,
Cliff