[Web-SIG] My original template API proposal
Ian Bicking
ianb at colorstudy.com
Sun Feb 5 00:21:45 CET 2006
Well, here's the proposal I had before, tweaked slightly. This is
mostly like the TG/Buffet API, but with find_resource extracted. I
realize this is the basis of the whole WSGI offshoot before, and maybe
an API without that would be useful or easier to implement. But it
would also be way more useful to me with a resource finding callback,
and I know Kevin has also indicated he wants that feature in TG.
It *is* hard to implement find_resource and will likely require updates
or monkeypatching of existing template systems, because they don't
always expose the internal process of fetching some other template.
The API is here:
http://svn.pythonpaste.org/home/ianb/templateapi/interface.py and copied
below:
"""
These interfaces represent two sides of a resource-fetching
implementation. ``IFindResource`` is meant to be implemented by the
framework, and can implement things like search paths.
``IResourceType`` produces resources.
Major open issues:
* Where does caching occur? What are the promises we can make about
caching? How can we know about the dependencies between templates,
so we know when a template has to be recompiled because something it
depends upon has been recompiled?
* How will this really be used for non-template resources? Most
immediately important is media files like CSS files, which are often
changed in concert with template changes, but are usually just
static.
* Should the expected output type be separate from the expected input
type? Right now IResourceType distinguishes template engines, but
doesn't necessarily distinguish the expected mime type.
Other questions are in [] in the docstrings below...
"""
class IResourceFinder:
def __call__(resource_name,
resource_type=None,
relative_to_name=None,
relative_to_object=None):
"""
Finds a resource by the given name. If this is being called
*by* a resource, then both ``relative_to_name`` and
``relative_to_object`` should be given.
The implementation of this callable is *not* part of a
template plugin, but is something provided by the framework.
This is only a callable; it could be created in such a way
that it is bound to the current request in a web environment,
or with any other implementation that seems appropriate.
``resource_name`` and ``relative_to_name`` are strings or
unicode objects.
``relative_to_object`` is something that ``find_resource()``
itself returned.
``resource_type`` is the type of object we are looking for, an
instance of IResourceType. If not given (or None) then this
object should try to determine the type itself, possibly
changing the name and calling itself recursively.
[I think there should be some convention on what names should
look like -- like filenames (with / separators), or like
module names...? Should they include extensions?]
"""
class IResourceType:
"""
A kind of resource, like 'cheetah templates' or 'CSS files'.
[Should this include some attribute with the mime type,
extensions, name of the type, ...?]
"""
def load_resource(resource_name, find_resource, resource_stream,
resource_location=None):
"""
Returns the resource. ``resource_name`` is an opaque
identifier, but should be kept.
``find_resource`` is the implementation of ``IResourceFinder``
that is creating the resource. This same implementation
should be used for any recursive resource fetching.
The resource content is given in ``resource_stream``, a
file-like object. [Does the caller close the file?]
``resource_location`` is a string identifier for the actual
location of the resource. This might be a filename, or some
other unambiguous representation of where the resource came
from. This is meant for use in tracebacks or debugging, and
is only meant to mean something to a human and is not used by
the resource itself.
"""
class ITemplatePlugin(IResourceType):
def __init__(extra_vars_func=None, options=None):
"""
Create a template plugin instance.
``extra_vars_func`` is a function that returns a dictionary
of 'standard' variables for the environment. ``options`` is
a dictionary of options for the template (e.g., compiler
settings) with no defined contents.
[Is ``extra_vars_func`` necessary? Couldn't it be handled by
a wrapper around ``render``?]
"""
def load_resource(...):
"""
Return an instance of the template. No interface for the
return value is defined, but the return value can be used
with ``render``.
Note that some templating languages don't work well with
``render``, so the returned resource may be the more useful
interface, and frameworks should allow users to get at this
return value directly. This value should typically be the
'native' template object for the template language.
"""
def render(template_instance, vars, format="html", fragment=False):
"""
Render the template instance (as returned by
``load_resource``) to a string or unicode object. [Should
there be some way to return metadata about what was rendered,
like the type of object being returned -- e.g., text/html or
text/plain]
``vars`` is typically a dictionary (-like object) of
variables for use in substitution.
format may be 'xhtml', 'plain', 'elementtree' etc., but
plugins may ignore that value. Depending on the value, the
return value may not be a string. However, the caller should
try to handle a string return value. For instance, if you
ask for 'elementtree' and get a string response, you should
be ready to call ``XML()`` on that string. [Should this
optionally be a list of formats, in order of preference?]
'fragment' indicates if an incomplete document
should be created (e.g., with no DOCTYPE); again templates
may ignore this.
"""
More information about the Web-SIG
mailing list