File: mako_templating.py

package info (click to toggle)
python-pyramid 1.2.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 3,172 kB
  • sloc: python: 27,115; makefile: 7
file content (156 lines) | stat: -rw-r--r-- 6,018 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import os
import sys
import threading

from zope.interface import implements
from zope.interface import Interface

from pyramid.asset import resolve_asset_spec
from pyramid.asset import abspath_from_asset_spec
from pyramid.exceptions import ConfigurationError
from pyramid.interfaces import ITemplateRenderer
from pyramid.settings import asbool
from pyramid.util import DottedNameResolver

from mako.lookup import TemplateLookup
from mako import exceptions

class IMakoLookup(Interface):
    pass

class PkgResourceTemplateLookup(TemplateLookup):
    """TemplateLookup subclass that handles asset specification URIs"""
    def adjust_uri(self, uri, relativeto):
        """Called from within a Mako template, avoids adjusting the
        uri if it looks like an asset specification"""
        # Don't adjust asset spec names
        if ':' in uri:
            return uri
        return TemplateLookup.adjust_uri(self, uri, relativeto)

    def get_template(self, uri):
        """Fetch a template from the cache, or check the filesystem
        for it
        
        In addition to the basic filesystem lookup, this subclass will
        use pkg_resource to load a file using the asset
        specification syntax.
        
        """
        isabs = os.path.isabs(uri)
        if (not isabs) and (':' in uri):
            try:
                if self.filesystem_checks:
                    return self._check(uri, self._collection[uri])
                else:
                    return self._collection[uri]
            except KeyError:
                pname, path = resolve_asset_spec(uri)
                srcfile = abspath_from_asset_spec(path, pname)
                if os.path.isfile(srcfile):
                    return self._load(srcfile, uri)
                raise exceptions.TopLevelLookupException(
                    "Can not locate template for uri %r" % uri)
        return TemplateLookup.get_template(self, uri)


registry_lock = threading.Lock() 

def renderer_factory(info):
    path = info.name
    registry = info.registry
    settings = info.settings
    lookup = registry.queryUtility(IMakoLookup)
    if lookup is None:
        reload_templates = settings.get('reload_templates', False)
        directories = settings.get('mako.directories', [])
        module_directory = settings.get('mako.module_directory', None)
        input_encoding = settings.get('mako.input_encoding', 'utf-8')
        error_handler = settings.get('mako.error_handler', None)
        default_filters = settings.get('mako.default_filters', 'h')
        imports = settings.get('mako.imports', None)
        strict_undefined = settings.get('mako.strict_undefined', 'false')
        preprocessor = settings.get('mako.preprocessor', None)
        if not hasattr(directories, '__iter__'):
            directories = filter(None, directories.splitlines())
        directories = [ abspath_from_asset_spec(d) for d in directories ]
        if module_directory is not None:
            module_directory = abspath_from_asset_spec(module_directory)
        if error_handler is not None:
            dotted = DottedNameResolver(info.package)
            error_handler = dotted.maybe_resolve(error_handler)
        if default_filters is not None:
            if not hasattr(default_filters, '__iter__'):
                default_filters = filter(None, default_filters.splitlines())
        if imports is not None:
            if not hasattr(imports, '__iter__'):
                imports = filter(None, imports.splitlines())
        strict_undefined = asbool(strict_undefined)
        if preprocessor is not None:
            dotted = DottedNameResolver(info.package)
            preprocessor = dotted.maybe_resolve(preprocessor)
            
        
        lookup = PkgResourceTemplateLookup(directories=directories,
                                           module_directory=module_directory,
                                           input_encoding=input_encoding,
                                           error_handler=error_handler,
                                           default_filters=default_filters,
                                           imports=imports,
                                           filesystem_checks=reload_templates,
                                           strict_undefined=strict_undefined,
                                           preprocessor=preprocessor)
        registry_lock.acquire()
        try:
            registry.registerUtility(lookup, IMakoLookup)
        finally:
            registry_lock.release()
            
    return MakoLookupTemplateRenderer(path, lookup)

class MakoRenderingException(Exception):
    def __init__(self, text):
        self.text = text

    def __repr__(self):
        return self.text

    __str__ = __repr__

class MakoLookupTemplateRenderer(object):
    implements(ITemplateRenderer)
    def __init__(self, path, lookup):
        self.path = path
        self.lookup = lookup
 
    def implementation(self):
        return self.lookup.get_template(self.path)

    def __call__(self, value, system):
        context = system.pop('context', None)
        if context is not None:
            system['_context'] = context
        def_name = None
        if isinstance(value, tuple):
            def_name, value = value
        try:
            system.update(value)
        except (TypeError, ValueError):
            raise ValueError('renderer was passed non-dictionary as value')
        template = self.implementation()
        if def_name is not None:
            template = template.get_def(def_name)
        try:
            result = template.render_unicode(**system)
        except:
            try:
                exc_info = sys.exc_info()
                errtext = exceptions.text_error_template().render(
                    error=exc_info[1],
                    traceback=exc_info[2]
                    )
                raise MakoRenderingException(errtext)
            finally:
                del exc_info

        return result