summaryrefslogtreecommitdiff
path: root/repoze/bfg/template.py
blob: 78529eb406408244a56cdc1b4527ddaba59acf77 (plain)
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
import os
import sys

from zope.component import queryUtility
from zope.component.interfaces import ComponentLookupError
from zope.component import getSiteManager

from zope.interface import classProvides
from zope.interface import implements

from webob import Response

from repoze.bfg.interfaces import IView
from repoze.bfg.interfaces import ITemplateFactory

class Z3CPTTemplateFactory(object):
    classProvides(ITemplateFactory)
    implements(IView)

    def __init__(self, path):
        from z3c.pt import PageTemplateFile
        self.template = PageTemplateFile(path)

    def __call__(self, *arg, **kw):
        result = self.template.render(**kw)
        response = Response(result)
        return response

class XSLTemplateFactory(object):
    classProvides(ITemplateFactory)
    implements(IView)

    def __init__(self, path):
        self.path = path

    def __call__(self, *arg, **kw):
        node = kw.get("node")
        processor = get_processor(self.path)
        result = str(processor(node))
        response = Response(result)
        return response

# Manage XSLT processors on a per-thread basis
import threading
from lxml import etree
xslt_pool = threading.local()
def get_processor(xslt_fn):
    try:
        return xslt_pool.processors[xslt_fn]
    except AttributeError:
        xslt_pool.processors = {}
    except KeyError:
        pass

    # Make a processor and add it to the pool
    source = etree.ElementTree(file=xslt_fn)
    proc = etree.XSLT(source)
    xslt_pool.processors[xslt_fn] = proc
    return proc

def package_path(package):
    return os.path.abspath(os.path.dirname(package.__file__))

def registerTemplate(template, path):
    try:
        sm = getSiteManager()
    except ComponentLookupError:
        pass
    else:
        sm.registerUtility(template, IView, name=path)

def render_template(path, **kw):
    """ Render a z3c.pt (ZPT) template at the package-relative path
    (may also be absolute) using the kwargs in ``*kw`` as top-level
    names and return a Response object. """
    # XXX use pkg_resources

    if not os.path.isabs(path):
        package_globals = sys._getframe(1).f_globals
        package_name = package_globals['__name__']
        package = sys.modules[package_name]
        prefix = package_path(package)
        path = os.path.join(prefix, path)

    template = queryUtility(IView, path)

    if template is None:
        if not os.path.exists(path):
            raise ValueError('Missing template file: %s' % path)
        template = Z3CPTTemplateFactory(path)
        registerTemplate(template, path)

    return template(**kw)

def render_transform(path, **kw):
    """ Render a XSL template at the package-relative path (may also
    be absolute) using the kwargs in ``*kw`` as top-level names and
    return a Response object."""
    # Render using XSLT

    if not os.path.isabs(path):
        package_globals = sys._getframe(1).f_globals
        package_name = package_globals['__name__']
        package = sys.modules[package_name]
        prefix = package_path(package)
        path = os.path.join(prefix, path)

    template = queryUtility(IView, path)
    node = kw.get("node")
    if template is None:
        if not os.path.exists(path):
            raise ValueError('Missing template file: %s' % path)
        template = XSLTemplateFactory(path)
        registerTemplate(template, path)

    return template(**kw)