""" These interfaces represent two sides of a template-fetching implementation. ``ITemplateFinder`` is meant to be implemented by the framework, and can implement things like search paths. ``ITemplateType`` produces templates. 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 ITemplateType distinguishes template engines, but doesn't necessarily distinguish the expected mime type. Other questions are in [] in the docstrings below... """ class ITemplateFinder: def __call__(template_name, template_type=None, relative_to_name=None, relative_to_object=None): """ Finds a template by the given name. If this is being called *by* a template, 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. ``template_name`` and ``relative_to_name`` are strings or unicode objects. ``relative_to_object`` is something that ``find_template()`` itself returned. ``template_type`` is the type of object we are looking for, an instance of ITemplateType. 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 ITemplatePlugin(ITemplateType): def __init__(options=None): """ Create a template plugin instance. ``options`` is a dictionary of options for the template (e.g., compiler settings) with no defined contents. """ def load_template(template_name, template_stream, find_template, template_location=None): """ Returns the template. ``template_name`` is an opaque identifier, but should be kept. ``find_template`` is the implementation of ``ITemplateFinder`` that is creating the template. This same implementation should be used for any recursive template fetching. [Because this is passed in here, a template can't be loaded on behalf of another finder] The template content is given in ``template_stream``, a file-like object. [Does the caller close the file?] ``template_location`` is a string identifier for the actual location of the template. This might be a filename, or some other unambiguous representation of where the template 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 template itself. 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 template 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, wsgi_environ=None, set_header_callback=None, **kwargs): """ Render the template instance (as returned by ``load_template``). [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. ``wsgi_environ``, if given, is the WSGI environment dictionary. Templates are free to create their own native wrappers of this environment. [Is there anything specifying where *here* is? Is SCRIPT_NAME authoritative in this case? Any standard for the application root? Maybe a special key, e.g., wsgi.application_root] ``set_header_callback`` is a function that can be called like ``set_header_callback(header_name, header_value)``. Arguments can only be strings (not unicode) [encode unicode with ASCII?]. The header named ``'Status'`` can be used to set the status. Even if this template is rendered in a web environment, frameworks may not provide this callback if they do not expect or wish the template to effect the headers. Other keyword arguments can be provided, with meaning specific to the templating language. Plugins should ignore keyword arguments they do not understand. [Is this a good idea?] This function returns an iterator which produces strings or unicode strings. (It should produce one or the other, not both.) Unicode is preferred. If you want a template to render to something else -- for example, ElementTree objects -- you should provide another method with the same signature as this. Consumers can fall back to getting the string with this method, like:: template = plugin.load_template(...) try: meth = plugin.render_elementtree except AttributeError: result = ''.join(plugin.render(template, ...)) result = ElementTree.XML(result) else: result = meth(template, ...) """