summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Everitt <paul@agendaless.com>2008-07-16 16:55:42 +0000
committerPaul Everitt <paul@agendaless.com>2008-07-16 16:55:42 +0000
commit231bc67350bd0269efce3203b83b76c7aa8d4eb1 (patch)
tree3d908b33b995c7ce98b9e18a12bded7387440924
parent22eed6aa7e8938ec30908aface102d42541dd3b3 (diff)
downloadpyramid-231bc67350bd0269efce3203b83b76c7aa8d4eb1.tar.gz
pyramid-231bc67350bd0269efce3203b83b76c7aa8d4eb1.tar.bz2
pyramid-231bc67350bd0269efce3203b83b76c7aa8d4eb1.zip
-rw-r--r--repoze/bfg/template.py52
-rw-r--r--repoze/bfg/tests/fixtures/minimal.xsl6
-rw-r--r--repoze/bfg/tests/test_xslt.py123
3 files changed, 181 insertions, 0 deletions
diff --git a/repoze/bfg/template.py b/repoze/bfg/template.py
index efb9f2c55..dd0778a43 100644
--- a/repoze/bfg/template.py
+++ b/repoze/bfg/template.py
@@ -26,6 +26,38 @@ class Z3CPTTemplateFactory(object):
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__))
@@ -56,3 +88,23 @@ def render_template(path, **kw):
registerTemplate(template, path)
return template(**kw)
+
+def render_transform(path, **kw):
+ # 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)
diff --git a/repoze/bfg/tests/fixtures/minimal.xsl b/repoze/bfg/tests/fixtures/minimal.xsl
new file mode 100644
index 000000000..56cebc643
--- /dev/null
+++ b/repoze/bfg/tests/fixtures/minimal.xsl
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:template match="/">
+ <div/>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/repoze/bfg/tests/test_xslt.py b/repoze/bfg/tests/test_xslt.py
new file mode 100644
index 000000000..448d49ddc
--- /dev/null
+++ b/repoze/bfg/tests/test_xslt.py
@@ -0,0 +1,123 @@
+import unittest
+
+from zope.component.testing import PlacelessSetup
+
+class Base(PlacelessSetup):
+ def setUp(self):
+ PlacelessSetup.setUp(self)
+
+ def tearDown(self):
+ PlacelessSetup.tearDown(self)
+
+ def _zcmlConfigure(self):
+ import repoze.bfg
+ import zope.configuration.xmlconfig
+ zope.configuration.xmlconfig.file('configure.zcml', package=repoze.bfg)
+
+ def _getTemplatePath(self, name):
+ import os
+ here = os.path.abspath(os.path.dirname(__file__))
+ return os.path.join(here, 'fixtures', name)
+
+class XSLTemplateFactoryTests(unittest.TestCase, Base):
+ def setUp(self):
+ Base.setUp(self)
+
+ def tearDown(self):
+ Base.tearDown(self)
+
+ def _getTargetClass(self):
+ from repoze.bfg.template import XSLTemplateFactory
+ return XSLTemplateFactory
+
+ def _makeOne(self, *arg, **kw):
+ klass = self._getTargetClass()
+ return klass(*arg, **kw)
+
+ def test_instance_conforms_to_IView(self):
+ from zope.interface.verify import verifyObject
+ from repoze.bfg.interfaces import IView
+ path = self._getTemplatePath('minimal.xsl')
+ verifyObject(IView, self._makeOne(path))
+
+ def test_class_conforms_to_IView(self):
+ from zope.interface.verify import verifyClass
+ from repoze.bfg.interfaces import IView
+ verifyClass(IView, self._getTargetClass())
+
+ def test_class_conforms_to_ITemplateFactory(self):
+ from zope.interface.verify import verifyObject
+ from repoze.bfg.interfaces import ITemplateFactory
+ verifyObject(ITemplateFactory, self._getTargetClass())
+
+ def test_call(self):
+ self._zcmlConfigure()
+ minimal = self._getTemplatePath('minimal.xsl')
+ instance = self._makeOne(minimal)
+ from lxml import etree
+ info = etree.Element("info")
+ result = instance(node=info)
+ from webob import Response
+ self.failUnless(isinstance(result, Response))
+ resultstr = """<?xml version="1.0"?>\n<div/>\n"""
+ self.assertEqual(result.app_iter, [resultstr])
+ self.assertEqual(result.status, '200 OK')
+ self.assertEqual(len(result.headerlist), 2)
+
+class RenderTemplateTests(unittest.TestCase, Base):
+ def setUp(self):
+ Base.setUp(self)
+
+ def tearDown(self):
+ Base.tearDown(self)
+
+ def _getFUT(self):
+ from repoze.bfg.template import render_transform
+ return render_transform
+
+ def test_nonabs_unregistered(self):
+ self._zcmlConfigure()
+ from zope.component import queryUtility
+ from repoze.bfg.interfaces import IView
+ minimal = self._getTemplatePath('minimal.xsl')
+ self.assertEqual(queryUtility(IView, minimal), None)
+ render = self._getFUT()
+ from lxml import etree
+ info = etree.Element("info")
+ result = render(minimal, node=info)
+ from webob import Response
+ self.failUnless(isinstance(result, Response))
+ resultstr = """<?xml version="1.0"?>\n<div/>\n"""
+ self.assertEqual(result.app_iter, [resultstr])
+ self.assertEqual(result.status, '200 OK')
+ self.assertEqual(len(result.headerlist), 2)
+ from repoze.bfg.template import XSLTemplateFactory
+ self.failUnless(isinstance(queryUtility(IView, minimal),
+ XSLTemplateFactory))
+
+ def test_nonabs_registered(self):
+ self._zcmlConfigure()
+ from zope.component import getGlobalSiteManager
+ from zope.component import queryUtility
+ from repoze.bfg.template import XSLTemplateFactory
+ from repoze.bfg.interfaces import IView
+ minimal = self._getTemplatePath('minimal.xsl')
+ utility = XSLTemplateFactory(minimal)
+ gsm = getGlobalSiteManager()
+ gsm.registerUtility(utility, IView, name=minimal)
+ render = self._getFUT()
+ from lxml import etree
+ info = etree.Element("info")
+ result = render(minimal, node=info)
+ from webob import Response
+ self.failUnless(isinstance(result, Response))
+ resultstr = """<?xml version="1.0"?>\n<div/>\n"""
+ self.assertEqual(result.app_iter, [resultstr])
+ self.assertEqual(result.status, '200 OK')
+ self.assertEqual(len(result.headerlist), 2)
+ self.assertEqual(queryUtility(IView, minimal), utility)
+
+class DummyView:
+ context = 'context'
+ request = 'request'
+