[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