paths.py 3.74 KB
Newer Older
1 2 3
"""
Set up lookup paths for mako templates.
"""
4 5

import hashlib
David Baumgold committed
6
import contextlib
7 8 9 10 11 12
import os
import pkg_resources

from django.conf import settings
from mako.lookup import TemplateLookup

13
from microsite_configuration import microsite
14 15 16 17 18 19 20 21
from . import LOOKUP


class DynamicTemplateLookup(TemplateLookup):
    """
    A specialization of the standard mako `TemplateLookup` class which allows
    for adding directories progressively.
    """
22 23 24 25
    def __init__(self, *args, **kwargs):
        super(DynamicTemplateLookup, self).__init__(*args, **kwargs)
        self.__original_module_directory = self.template_args['module_directory']

David Baumgold committed
26 27 28
    def __repr__(self):
        return "<{0.__class__.__name__} {0.directories}>".format(self)

29
    def add_directory(self, directory, prepend=False):
30 31 32
        """
        Add a new directory to the template lookup path.
        """
33 34 35 36
        if prepend:
            self.directories.insert(0, os.path.normpath(directory))
        else:
            self.directories.append(os.path.normpath(directory))
37

38 39 40 41 42 43 44 45 46 47 48 49
        # Since the lookup path has changed, the compiled modules might be
        # wrong because now "foo.html" might be a completely different template,
        # and "foo.html.py" in the module directory has no way to know that.
        # Update the module_directory argument to point to a directory
        # specifically for this lookup path.
        unique = hashlib.md5(":".join(str(d) for d in self.directories)).hexdigest()
        self.template_args['module_directory'] = os.path.join(self.__original_module_directory, unique)

        # Also clear the internal caches. Ick.
        self._collection.clear()
        self._uri_cache.clear()

50 51 52 53 54 55 56 57 58 59 60 61
    def get_template(self, uri):
        """
        Overridden method which will hand-off the template lookup to the microsite subsystem
        """
        microsite_template = microsite.get_template(uri)

        return (
            microsite_template
            if microsite_template
            else super(DynamicTemplateLookup, self).get_template(uri)
        )

62

63 64 65 66 67 68 69
def clear_lookups(namespace):
    """
    Remove mako template lookups for the given namespace.
    """
    if namespace in LOOKUP:
        del LOOKUP[namespace]

70

71
def add_lookup(namespace, directory, package=None, prepend=False):
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
    """
    Adds a new mako template lookup directory to the given namespace.

    If `package` is specified, `pkg_resources` is used to look up the directory
    inside the given package.  Otherwise `directory` is assumed to be a path
    in the filesystem.
    """
    templates = LOOKUP.get(namespace)
    if not templates:
        LOOKUP[namespace] = templates = DynamicTemplateLookup(
            module_directory=settings.MAKO_MODULE_DIR,
            output_encoding='utf-8',
            input_encoding='utf-8',
            default_filters=['decode.utf8'],
            encoding_errors='replace',
        )
    if package:
        directory = pkg_resources.resource_filename(package, directory)
90
    templates.add_directory(directory, prepend=prepend)
91 92 93 94 95 96 97


def lookup_template(namespace, name):
    """
    Look up a Mako template by namespace and name.
    """
    return LOOKUP[namespace].get_template(name)
David Baumgold committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120


@contextlib.contextmanager
def save_lookups():
    """
    A context manager to save and restore the Mako template lookup path.

    Useful for testing.

    """
    # Make a copy of the list of directories for each namespace.
    namespace_dirs = {namespace: list(look.directories) for namespace, look in LOOKUP.items()}

    try:
        yield
    finally:
        # Get rid of all the lookups.
        LOOKUP.clear()

        # Re-create the lookups from our saved list.
        for namespace, directories in namespace_dirs.items():
            for directory in directories:
                add_lookup(namespace, directory)