Source code for pipeline.infrastructure.renderer.weblog

"""
Created on 8 Sep 2014

@author: sjw
"""
import atexit
import fnmatch
import os
import pkg_resources
import shutil
import tempfile

import mako.lookup
import mako.template

import pipeline.infrastructure.logging
import pipeline.infrastructure.renderer.templates
from .registry import RendererRegistry

LOG = pipeline.infrastructure.logging.get_logger(__name__)


# enumerations for registering web log renderers
UNGROUPED = 'ungrouped'
BY_SESSION = 'by_session'


def _get_template_lookup():
    """
    Create a Mako TemplateLookup object to which all pipeline templates will
    be registered. Compiled templates are stored in a temporary working
    directory which is deleted on process exit.
    """
    tmpdir = tempfile.mkdtemp()
    LOG.trace('Mako module directory = %s' % tmpdir)
    # Remove temporary Mako codegen directory on termination of Python process
    atexit.register(lambda: shutil.rmtree(tmpdir,
                                          ignore_errors=True))

    templates_path = pkg_resources.resource_filename(pipeline.infrastructure.renderer.templates.__name__, '')
    lookup = mako.lookup.TemplateLookup(directories=[templates_path],
                                        module_directory=tmpdir,
                                        input_encoding='utf-8',
                                        default_filters=['decode.utf8'])
    return lookup
TEMPLATE_LOOKUP = _get_template_lookup()


[docs]def register_mako_templates(directory, prefix=''): """ Find Mako templates in the given directory, registering them to the module template lookup. Templates will be registered to a URI composed of the URI prefix argument (optional) plus the template filename, minus filename extension. For example, a call with prefix='hif' finding a file called 'importdata.mako' would register the template to the Mako URI 'hif/importdata'. """ # get relative paths to all Mako templates in the directory relpaths = fnmatch.filter(os.listdir(directory), '*.mako') # convert them to absolute paths for lookup registration abspaths = [os.path.join(directory, t) for t in relpaths] if directory not in TEMPLATE_LOOKUP.directories: TEMPLATE_LOOKUP.directories.append(directory)
# # TODO replace with explicit registration for control over URIs # for template_path in abspaths: # # postponed until task import is removed from htmlrenderer # root, _ = os.path.splitext(os.path.basename(template_path)) # uri = os.path.join(prefix, root) # # t = mako.template.Template(filename=template_path, # format_exceptions=True, # module_directory=TEMPLATE_LOOKUP.module_directory, # lookup=TEMPLATE_LOOKUP, # uri=uri) # # TEMPLATE_LOOKUP.put_template(uri, t) # LOG.trace('%s registered to URI %s', template_path, uri)
[docs]class WebLogRendererRegistry(RendererRegistry): def __init__(self): super(WebLogRendererRegistry, self).__init__() self._render_by_session = set() self._render_ungrouped = set()
[docs] def add_renderer(self, task_cls, renderer, group_by=None, key_fn=None, key=None): """ Register a renderer to be used to generate HTML for results from a given task. There are two modes of registration: 1. registration of a context-specific renderer 2. registration of a universal renderer, which wil be used if no context-specific renderer is found Context-specific renderers are registered by supplying key and key_fn arguments. key_fn should be a function that accepts a context and returns a key from it. This key is used to look up the renderer. Specifying a key value of 'X' says 'this renderer should be used for this task if this key_fn returns 'X' for this context'. :param task_cls: the target pipeline Task class :param renderer: the renderer to use for the task :param group_by: grouping directive - either "session" or "ungrouped" :param key: optional key to retrieve this renderer by :param key_fn: optional function that accepts a pipeline context and returns the renderer key :return: """ super(WebLogRendererRegistry, self).add_renderer(task_cls, renderer, key_fn, key) if group_by == 'session': self._render_by_session.add(task_cls.__name__) elif group_by == 'ungrouped': self._render_ungrouped.add(task_cls.__name__) else: LOG.warning('{} did not register a renderer group type. Assuming it is grouped by ' 'session'.format( task_cls.__name__)) self._render_by_session.add(task_cls.__name__)
[docs] def render_by_session(self, task_name): return task_name in self._render_by_session
[docs] def render_ungrouped(self, task_name): return task_name in self._render_ungrouped
registry = WebLogRendererRegistry() # this function exists at the module level to retain compatibility with # pre-RenderRegistry code.
[docs]def add_renderer(*args, **kwargs): registry.add_renderer(*args, **kwargs)