diff options
| author | Chris McDonough <chrism@agendaless.com> | 2008-09-26 06:42:53 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2008-09-26 06:42:53 +0000 |
| commit | 01a6e567a20096f6033cc603667f4e900d2a44c3 (patch) | |
| tree | a87431383a63dbafbb5cccdfa7679b9187bdfc29 /repoze | |
| parent | 26216e5526ca56d886d2348f9e1f09b86622aa72 (diff) | |
| download | pyramid-01a6e567a20096f6033cc603667f4e900d2a44c3.tar.gz pyramid-01a6e567a20096f6033cc603667f4e900d2a44c3.tar.bz2 pyramid-01a6e567a20096f6033cc603667f4e900d2a44c3.zip | |
Move to Chameleon.
Diffstat (limited to 'repoze')
| -rw-r--r-- | repoze/bfg/chameleon_genshi.py | 82 | ||||
| -rw-r--r-- | repoze/bfg/chameleon_zpt.py | 81 | ||||
| -rw-r--r-- | repoze/bfg/configure.zcml | 4 | ||||
| -rw-r--r-- | repoze/bfg/includes/configure.zcml | 4 | ||||
| -rw-r--r-- | repoze/bfg/paster_template/+package+/views.py_tmpl | 2 | ||||
| -rw-r--r-- | repoze/bfg/push.py | 6 | ||||
| -rw-r--r-- | repoze/bfg/template.py | 151 | ||||
| -rw-r--r-- | repoze/bfg/tests/fixtures/minimal.genshi | 3 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_chameleon_genshi.py | 134 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_chameleon_zpt.py | 139 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_push.py | 2 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_template.py | 61 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_xslt.py | 14 | ||||
| -rw-r--r-- | repoze/bfg/xslt.py | 85 | ||||
| -rw-r--r-- | repoze/bfg/zcml.py | 2 |
15 files changed, 562 insertions, 208 deletions
diff --git a/repoze/bfg/chameleon_genshi.py b/repoze/bfg/chameleon_genshi.py new file mode 100644 index 000000000..fbcc519e6 --- /dev/null +++ b/repoze/bfg/chameleon_genshi.py @@ -0,0 +1,82 @@ +import os + +from webob import Response + +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 repoze.bfg.path import caller_path +from repoze.bfg.interfaces import ITemplateFactory +from repoze.bfg.interfaces import ITemplate +from repoze.bfg.interfaces import ISettings + +from chameleon.genshi.template import GenshiTemplateFile + +class GenshiTemplateFactory(object): + classProvides(ITemplateFactory) + implements(ITemplate) + + def __init__(self, path, auto_reload=False): + try: + self.template = GenshiTemplateFile(path, auto_reload=auto_reload) + except ImportError, why: + why = str(why) + if 'z3c.pt' in why: + # unpickling error due to move from z3c.pt -> chameleon + cachefile = '%s.cache' % path + if os.path.isfile(cachefile): + os.remove(cachefile) + self.template = GenshiTemplateFile(path, + auto_reload=auto_reload) + else: + raise + + def __call__(self, **kw): + result = self.template.render(**kw) + return result + +def _get_template(path, **kw): + # XXX use pkg_resources + template = queryUtility(ITemplate, path) + + if template is None: + if not os.path.exists(path): + raise ValueError('Missing template file: %s' % path) + settings = queryUtility(ISettings) + auto_reload = settings and settings.reload_templates + template = GenshiTemplateFactory(path, auto_reload) + try: + sm = getSiteManager() + except ComponentLookupError: + pass + else: + sm.registerUtility(template, ITemplate, name=path) + + return template + +def get_template(path): + """ Return a ``chameleon.genshi`` template object at the + package-relative path (may also be absolute)""" + path = caller_path(path) + return _get_template(path).template + +def render_template(path, **kw): + """ Render a ``chameleon.genshi`` template at the package-relative + path (may also be absolute) using the kwargs in ``*kw`` as + top-level names and return a string.""" + path = caller_path(path) + template = get_template(path) + return template(**kw) + +def render_template_to_response(path, **kw): + """ Render a ``chameleon.genshi`` template at the package-relative + path (may also be absolute) using the kwargs in ``*kw`` as + top-level names and return a Response object.""" + path = caller_path(path) + result = render_template(path, **kw) + return Response(result) + diff --git a/repoze/bfg/chameleon_zpt.py b/repoze/bfg/chameleon_zpt.py new file mode 100644 index 000000000..80669c009 --- /dev/null +++ b/repoze/bfg/chameleon_zpt.py @@ -0,0 +1,81 @@ +import os + +from webob import Response + +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 repoze.bfg.path import caller_path +from repoze.bfg.interfaces import ITemplateFactory +from repoze.bfg.interfaces import ITemplate +from repoze.bfg.interfaces import ISettings + +from chameleon.zpt.template import PageTemplateFile + +class ZPTTemplateFactory(object): + classProvides(ITemplateFactory) + implements(ITemplate) + + def __init__(self, path, auto_reload=False): + try: + self.template = PageTemplateFile(path, auto_reload=auto_reload) + except ImportError, why: + why = str(why) + if 'z3c.pt' in why: + # unpickling error due to move from z3c.pt -> chameleon + cachefile = '%s.cache' % path + if os.path.isfile(cachefile): + os.remove(cachefile) + self.template = PageTemplateFile(path, auto_reload=auto_reload) + else: + raise + + def __call__(self, **kw): + result = self.template.render(**kw) + return result + +def _get_template(path, **kw): + # XXX use pkg_resources + template = queryUtility(ITemplate, path) + + if template is None: + if not os.path.exists(path): + raise ValueError('Missing template file: %s' % path) + settings = queryUtility(ISettings) + auto_reload = settings and settings.reload_templates + template = ZPTTemplateFactory(path, auto_reload) + try: + sm = getSiteManager() + except ComponentLookupError: + pass + else: + sm.registerUtility(template, ITemplate, name=path) + + return template + +def get_template(path): + """ Return a ``chameleon.zpt`` template object at the + package-relative path (may also be absolute)""" + path = caller_path(path) + return _get_template(path).template + +def render_template(path, **kw): + """ Render a ``chameleon.zpt`` template at the package-relative + path (may also be absolute) using the kwargs in ``*kw`` as + top-level names and return a string.""" + path = caller_path(path) + template = get_template(path) + return template(**kw) + +def render_template_to_response(path, **kw): + """ Render a ``chameleon.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.""" + path = caller_path(path) + result = render_template(path, **kw) + return Response(result) + diff --git a/repoze/bfg/configure.zcml b/repoze/bfg/configure.zcml index 355795b7c..517b5fd54 100644 --- a/repoze/bfg/configure.zcml +++ b/repoze/bfg/configure.zcml @@ -3,7 +3,9 @@ <!-- superseded by includes/configure.zcml --> - <include package="z3c.pt" /> + <include package="zope.component" file="meta.zcml" /> + + <include package="chameleon.zpt" file="configure.zcml"/> <adapter factory=".traversal.ModelGraphTraverser" diff --git a/repoze/bfg/includes/configure.zcml b/repoze/bfg/includes/configure.zcml index e25d749ca..e758fb192 100644 --- a/repoze/bfg/includes/configure.zcml +++ b/repoze/bfg/includes/configure.zcml @@ -1,7 +1,9 @@ <configure xmlns="http://namespaces.zope.org/zope" i18n_domain="repoze.bfg"> - <include package="z3c.pt" /> + <include package="zope.component" file="meta.zcml" /> + + <include package="chameleon.zpt" file="configure.zcml"/> <adapter factory="repoze.bfg.traversal.ModelGraphTraverser" diff --git a/repoze/bfg/paster_template/+package+/views.py_tmpl b/repoze/bfg/paster_template/+package+/views.py_tmpl index d3824826a..8a2836171 100644 --- a/repoze/bfg/paster_template/+package+/views.py_tmpl +++ b/repoze/bfg/paster_template/+package+/views.py_tmpl @@ -1,4 +1,4 @@ -from repoze.bfg.template import render_template_to_response +from repoze.bfg.chameleon_zpt import render_template_to_response def my_view(context, request): return render_template_to_response('templates/mytemplate.pt', diff --git a/repoze/bfg/push.py b/repoze/bfg/push.py index 61b2f9cf0..9b3197cf6 100644 --- a/repoze/bfg/push.py +++ b/repoze/bfg/push.py @@ -1,8 +1,8 @@ import os.path -from repoze.bfg.template import render_template_to_response +from repoze.bfg.chameleon_zpt import render_template_to_response class pushpage(object): - """ Decorator for functions which return ZPT template namespaces. + """ Decorator for functions which return Chameleon template namespaces. E.g.:: @@ -12,7 +12,7 @@ class pushpage(object): Equates to:: - from repoze.bfg.template import render_template_to_response + from repoze.bfg.chameleon import render_template_to_response def my_view(context, request): return render_template_to_response('www/my_template.pt', a=1, b=()) diff --git a/repoze/bfg/template.py b/repoze/bfg/template.py index e501b2592..2f3017bd6 100644 --- a/repoze/bfg/template.py +++ b/repoze/bfg/template.py @@ -1,138 +1,13 @@ -import os - -from webob import Response - -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 repoze.bfg.path import caller_path -from repoze.bfg.interfaces import ITemplateFactory -from repoze.bfg.interfaces import ITemplate -from repoze.bfg.interfaces import INodeTemplate -from repoze.bfg.interfaces import ISettings - -class Z3CPTTemplateFactory(object): - classProvides(ITemplateFactory) - implements(ITemplate) - - def __init__(self, path, auto_reload=False): - try: - from z3c.pt import PageTempateFile - except ImportError: - # after 1.0a7 - from z3c.pt.pagetemplate import PageTemplateFile - try: - self.template = PageTemplateFile(path, auto_reload=auto_reload) - except TypeError: - # z3c.pt before 1.0 - self.template = PageTemplateFile(path) - - def __call__(self, **kw): - result = self.template.render(**kw) - return result - -class XSLTemplateFactory(object): - classProvides(ITemplateFactory) - implements(INodeTemplate) - - def __init__(self, path, auto_reload=False): - self.path = path - self.auto_reload = auto_reload - - def __call__(self, node, **kw): - processor = get_processor(self.path, self.auto_reload) - result = str(processor(node, **kw)) - return result - -# Manage XSLT processors on a per-thread basis -import threading -from lxml import etree -xslt_pool = threading.local() -def get_processor(xslt_fn, auto_reload=False): - if not auto_reload: - 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 registerTemplate(type, template, path): - try: - sm = getSiteManager() - except ComponentLookupError: - pass - else: - sm.registerUtility(template, type, name=path) - -def _get_template(path, **kw): - # XXX use pkg_resources - template = queryUtility(ITemplate, path) - - if template is None: - if not os.path.exists(path): - raise ValueError('Missing template file: %s' % path) - settings = queryUtility(ISettings) - auto_reload = settings and settings.reload_templates - template = Z3CPTTemplateFactory(path, auto_reload) - registerTemplate(ITemplate, template, path) - - return template - -def get_template(path): - """ Return a z3c.pt template object at the package-relative path - (may also be absolute) """ - path = caller_path(path) - return _get_template(path).template - -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 string. """ - path = caller_path(path) - template = get_template(path) - return template(**kw) - -def render_template_to_response(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. """ - path = caller_path(path) - result = render_template(path, **kw) - return Response(result) - -def render_transform(path, node, **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 string.""" - # Render using XSLT - path = caller_path(path) - - template = queryUtility(INodeTemplate, path) - if template is None: - if not os.path.exists(path): - raise ValueError('Missing template file: %s' % path) - template = XSLTemplateFactory(path) - registerTemplate(INodeTemplate, template, path) - - return template(node, **kw) - -def render_transform_to_response(path, node, **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.""" - path = caller_path(path) - result = render_transform(path, node, **kw) - return Response(result) - - +# The definitions in this module are import aliases for backwards +# compatibility; there are no plans to make this module itself go +# away, but the ``get_template``, ``render_template``, and +# ``render_template_to_response`` APIs should be imported from +# ``repoze.bfg.chameleon_zpt`` in the future for optimum correctness, +# while the ``render_transform`` and ``render_transform_to_response`` +# APIs should be imported from ``repoze.bfg.xsl``. + +from repoze.bfg.chameleon_zpt import get_template +from repoze.bfg.chameleon_zpt import render_template +from repoze.bfg.chameleon_zpt import render_template_to_response +from repoze.bfg.xslt import render_transform +from repoze.bfg.xslt import render_transform_to_response diff --git a/repoze/bfg/tests/fixtures/minimal.genshi b/repoze/bfg/tests/fixtures/minimal.genshi new file mode 100644 index 000000000..bd619a9da --- /dev/null +++ b/repoze/bfg/tests/fixtures/minimal.genshi @@ -0,0 +1,3 @@ +<div xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/"> +</div> diff --git a/repoze/bfg/tests/test_chameleon_genshi.py b/repoze/bfg/tests/test_chameleon_genshi.py new file mode 100644 index 000000000..0f0fc88a1 --- /dev/null +++ b/repoze/bfg/tests/test_chameleon_genshi.py @@ -0,0 +1,134 @@ +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 GenshiTemplateFactoryTests(unittest.TestCase, Base): + def setUp(self): + Base.setUp(self) + + def tearDown(self): + Base.tearDown(self) + + def _getTargetClass(self): + from repoze.bfg.chameleon_genshi import GenshiTemplateFactory + return GenshiTemplateFactory + + def _makeOne(self, *arg, **kw): + klass = self._getTargetClass() + return klass(*arg, **kw) + + def test_instance_implements_ITemplate(self): + from zope.interface.verify import verifyObject + from repoze.bfg.interfaces import ITemplate + path = self._getTemplatePath('minimal.genshi') + verifyObject(ITemplate, self._makeOne(path)) + + def test_class_implements_ITemplate(self): + from zope.interface.verify import verifyClass + from repoze.bfg.interfaces import ITemplate + verifyClass(ITemplate, self._getTargetClass()) + + def test_call(self): + self._zcmlConfigure() + minimal = self._getTemplatePath('minimal.genshi') + instance = self._makeOne(minimal) + result = instance() + self.failUnless(isinstance(result, str)) + self.assertEqual(result, '<div>\n</div>\n') + +class RenderTemplateTests(unittest.TestCase, Base): + def setUp(self): + Base.setUp(self) + + def tearDown(self): + Base.tearDown(self) + + def _getFUT(self): + from repoze.bfg.chameleon_genshi import render_template + return render_template + + def test_it(self): + minimal = self._getTemplatePath('minimal.genshi') + render = self._getFUT() + result = render(minimal) + self.failUnless(isinstance(result, str)) + self.assertEqual(result, '<div>\n</div>\n') + +class RenderTemplateToResponseTests(unittest.TestCase, Base): + def setUp(self): + Base.setUp(self) + + def tearDown(self): + Base.tearDown(self) + + def _getFUT(self): + from repoze.bfg.chameleon_genshi import render_template_to_response + return render_template_to_response + + def test_it(self): + minimal = self._getTemplatePath('minimal.genshi') + render = self._getFUT() + result = render(minimal) + from webob import Response + self.failUnless(isinstance(result, Response)) + self.assertEqual(result.app_iter, ['<div>\n</div>\n']) + self.assertEqual(result.status, '200 OK') + self.assertEqual(len(result.headerlist), 2) + +class GetTemplateTests(unittest.TestCase, Base): + def setUp(self): + Base.setUp(self) + + def tearDown(self): + Base.tearDown(self) + + def _getFUT(self): + from repoze.bfg.chameleon_genshi import get_template + return get_template + + def test_nonabs_registered(self): + from zope.component import getGlobalSiteManager + from zope.component import queryUtility + from repoze.bfg.chameleon_genshi import GenshiTemplateFactory + from repoze.bfg.interfaces import ITemplate + minimal = self._getTemplatePath('minimal.genshi') + utility = GenshiTemplateFactory(minimal) + gsm = getGlobalSiteManager() + gsm.registerUtility(utility, ITemplate, name=minimal) + get = self._getFUT() + result = get(minimal) + self.assertEqual(result.filename, minimal) + self.assertEqual(queryUtility(ITemplate, minimal), utility) + + def test_nonabs_unregistered(self): + from zope.component import getGlobalSiteManager + from zope.component import queryUtility + from repoze.bfg.chameleon_genshi import GenshiTemplateFactory + from repoze.bfg.interfaces import ITemplate + minimal = self._getTemplatePath('minimal.genshi') + self.assertEqual(queryUtility(ITemplate, minimal), None) + utility = GenshiTemplateFactory(minimal) + gsm = getGlobalSiteManager() + gsm.registerUtility(utility, ITemplate, name=minimal) + get = self._getFUT() + result = get(minimal) + self.assertEqual(result.filename, minimal) + self.assertEqual(queryUtility(ITemplate, minimal), utility) + diff --git a/repoze/bfg/tests/test_chameleon_zpt.py b/repoze/bfg/tests/test_chameleon_zpt.py new file mode 100644 index 000000000..3b977bcbf --- /dev/null +++ b/repoze/bfg/tests/test_chameleon_zpt.py @@ -0,0 +1,139 @@ +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 ZPTTemplateFactoryTests(unittest.TestCase, Base): + def setUp(self): + Base.setUp(self) + + def tearDown(self): + Base.tearDown(self) + + def _getTargetClass(self): + from repoze.bfg.chameleon_zpt import ZPTTemplateFactory + return ZPTTemplateFactory + + def _makeOne(self, *arg, **kw): + klass = self._getTargetClass() + return klass(*arg, **kw) + + def test_instance_implements_ITemplate(self): + from zope.interface.verify import verifyObject + from repoze.bfg.interfaces import ITemplate + path = self._getTemplatePath('minimal.pt') + verifyObject(ITemplate, self._makeOne(path)) + + def test_class_implements_ITemplate(self): + from zope.interface.verify import verifyClass + from repoze.bfg.interfaces import ITemplate + verifyClass(ITemplate, self._getTargetClass()) + + def test_call(self): + self._zcmlConfigure() + minimal = self._getTemplatePath('minimal.pt') + instance = self._makeOne(minimal) + result = instance() + self.failUnless(isinstance(result, str)) + self.assertEqual(result, '<div>\n</div>\n') + +class RenderTemplateTests(unittest.TestCase, Base): + def setUp(self): + Base.setUp(self) + + def tearDown(self): + Base.tearDown(self) + + def _getFUT(self): + from repoze.bfg.chameleon_zpt import render_template + return render_template + + def test_it(self): + self._zcmlConfigure() + minimal = self._getTemplatePath('minimal.pt') + render = self._getFUT() + result = render(minimal) + self.failUnless(isinstance(result, str)) + self.assertEqual(result, '<div>\n</div>\n') + +class RenderTemplateToResponseTests(unittest.TestCase, Base): + def setUp(self): + Base.setUp(self) + + def tearDown(self): + Base.tearDown(self) + + def _getFUT(self): + from repoze.bfg.chameleon_zpt import render_template_to_response + return render_template_to_response + + def test_it(self): + self._zcmlConfigure() + minimal = self._getTemplatePath('minimal.pt') + render = self._getFUT() + result = render(minimal) + from webob import Response + self.failUnless(isinstance(result, Response)) + self.assertEqual(result.app_iter, ['<div>\n</div>\n']) + self.assertEqual(result.status, '200 OK') + self.assertEqual(len(result.headerlist), 2) + +class GetTemplateTests(unittest.TestCase, Base): + def setUp(self): + Base.setUp(self) + + def tearDown(self): + Base.tearDown(self) + + def _getFUT(self): + from repoze.bfg.chameleon_zpt import get_template + return get_template + + def test_nonabs_registered(self): + self._zcmlConfigure() + from zope.component import getGlobalSiteManager + from zope.component import queryUtility + from repoze.bfg.chameleon_zpt import ZPTTemplateFactory + from repoze.bfg.interfaces import ITemplate + minimal = self._getTemplatePath('minimal.pt') + utility = ZPTTemplateFactory(minimal) + gsm = getGlobalSiteManager() + gsm.registerUtility(utility, ITemplate, name=minimal) + get = self._getFUT() + result = get(minimal) + self.assertEqual(result.filename, minimal) + self.assertEqual(queryUtility(ITemplate, minimal), utility) + + def test_nonabs_unregistered(self): + self._zcmlConfigure() + from zope.component import getGlobalSiteManager + from zope.component import queryUtility + from repoze.bfg.chameleon_zpt import ZPTTemplateFactory + from repoze.bfg.interfaces import ITemplate + minimal = self._getTemplatePath('minimal.pt') + self.assertEqual(queryUtility(ITemplate, minimal), None) + utility = ZPTTemplateFactory(minimal) + gsm = getGlobalSiteManager() + gsm.registerUtility(utility, ITemplate, name=minimal) + get = self._getFUT() + result = get(minimal) + self.assertEqual(result.filename, minimal) + self.assertEqual(queryUtility(ITemplate, minimal), utility) + + diff --git a/repoze/bfg/tests/test_push.py b/repoze/bfg/tests/test_push.py index 907503983..3dc456b58 100644 --- a/repoze/bfg/tests/test_push.py +++ b/repoze/bfg/tests/test_push.py @@ -31,7 +31,7 @@ class Test_pushpage(unittest.TestCase, PlacelessSetup): pp = self._makeOne('pp.pt') wrapped = pp(to_wrap) response = wrapped(object(), object()) - self.assertEqual(response.body, '<p>WRAPPED</p>') + self.assertEqual(response.body, '<p>WRAPPED</p>\n') def to_wrap(context, request): return {'wrapped': 'WRAPPED'} diff --git a/repoze/bfg/tests/test_template.py b/repoze/bfg/tests/test_template.py index ba3745132..42baa6492 100644 --- a/repoze/bfg/tests/test_template.py +++ b/repoze/bfg/tests/test_template.py @@ -19,40 +19,6 @@ class Base(PlacelessSetup): here = os.path.abspath(os.path.dirname(__file__)) return os.path.join(here, 'fixtures', name) -class Z3CPTTemplateFactoryTests(unittest.TestCase, Base): - def setUp(self): - Base.setUp(self) - - def tearDown(self): - Base.tearDown(self) - - def _getTargetClass(self): - from repoze.bfg.template import Z3CPTTemplateFactory - return Z3CPTTemplateFactory - - def _makeOne(self, *arg, **kw): - klass = self._getTargetClass() - return klass(*arg, **kw) - - def test_instance_implements_ITemplate(self): - from zope.interface.verify import verifyObject - from repoze.bfg.interfaces import ITemplate - path = self._getTemplatePath('minimal.pt') - verifyObject(ITemplate, self._makeOne(path)) - - def test_class_implements_ITemplate(self): - from zope.interface.verify import verifyClass - from repoze.bfg.interfaces import ITemplate - verifyClass(ITemplate, self._getTargetClass()) - - def test_call(self): - self._zcmlConfigure() - minimal = self._getTemplatePath('minimal.pt') - instance = self._makeOne(minimal) - result = instance() - self.failUnless(isinstance(result, str)) - self.assertEqual(result, '<div>\n</div>') - class RenderTemplateTests(unittest.TestCase, Base): def setUp(self): Base.setUp(self) @@ -70,7 +36,7 @@ class RenderTemplateTests(unittest.TestCase, Base): render = self._getFUT() result = render(minimal) self.failUnless(isinstance(result, str)) - self.assertEqual(result, '<div>\n</div>') + self.assertEqual(result, '<div>\n</div>\n') class RenderTemplateToResponseTests(unittest.TestCase, Base): def setUp(self): @@ -90,7 +56,7 @@ class RenderTemplateToResponseTests(unittest.TestCase, Base): result = render(minimal) from webob import Response self.failUnless(isinstance(result, Response)) - self.assertEqual(result.app_iter, ['<div>\n</div>']) + self.assertEqual(result.app_iter, ['<div>\n</div>\n']) self.assertEqual(result.status, '200 OK') self.assertEqual(len(result.headerlist), 2) @@ -109,10 +75,10 @@ class GetTemplateTests(unittest.TestCase, Base): self._zcmlConfigure() from zope.component import getGlobalSiteManager from zope.component import queryUtility - from repoze.bfg.template import Z3CPTTemplateFactory + from repoze.bfg.chameleon_zpt import ZPTTemplateFactory from repoze.bfg.interfaces import ITemplate minimal = self._getTemplatePath('minimal.pt') - utility = Z3CPTTemplateFactory(minimal) + utility = ZPTTemplateFactory(minimal) gsm = getGlobalSiteManager() gsm.registerUtility(utility, ITemplate, name=minimal) get = self._getFUT() @@ -124,11 +90,11 @@ class GetTemplateTests(unittest.TestCase, Base): self._zcmlConfigure() from zope.component import getGlobalSiteManager from zope.component import queryUtility - from repoze.bfg.template import Z3CPTTemplateFactory + from repoze.bfg.chameleon_zpt import ZPTTemplateFactory from repoze.bfg.interfaces import ITemplate minimal = self._getTemplatePath('minimal.pt') self.assertEqual(queryUtility(ITemplate, minimal), None) - utility = Z3CPTTemplateFactory(minimal) + utility = ZPTTemplateFactory(minimal) gsm = getGlobalSiteManager() gsm.registerUtility(utility, ITemplate, name=minimal) get = self._getFUT() @@ -136,18 +102,3 @@ class GetTemplateTests(unittest.TestCase, Base): self.assertEqual(result.filename, minimal) self.assertEqual(queryUtility(ITemplate, minimal), utility) - def test_nonabs_registered(self): - self._zcmlConfigure() - from zope.component import getGlobalSiteManager - from zope.component import queryUtility - from repoze.bfg.template import Z3CPTTemplateFactory - from repoze.bfg.interfaces import ITemplate - minimal = self._getTemplatePath('minimal.pt') - utility = Z3CPTTemplateFactory(minimal) - gsm = getGlobalSiteManager() - gsm.registerUtility(utility, ITemplate, name=minimal) - get = self._getFUT() - result = get(minimal) - self.assertEqual(result.filename, minimal) - self.assertEqual(queryUtility(ITemplate, minimal), utility) - diff --git a/repoze/bfg/tests/test_xslt.py b/repoze/bfg/tests/test_xslt.py index 01e5befba..0a858e08b 100644 --- a/repoze/bfg/tests/test_xslt.py +++ b/repoze/bfg/tests/test_xslt.py @@ -27,7 +27,7 @@ class XSLTemplateFactoryTests(unittest.TestCase, Base): Base.tearDown(self) def _getTargetClass(self): - from repoze.bfg.template import XSLTemplateFactory + from repoze.bfg.xslt import XSLTemplateFactory return XSLTemplateFactory def _makeOne(self, *arg, **kw): @@ -64,7 +64,7 @@ class RenderTransformToResponseTests(unittest.TestCase, Base): Base.tearDown(self) def _getFUT(self): - from repoze.bfg.template import render_transform_to_response + from repoze.bfg.xslt import render_transform_to_response return render_transform_to_response def test_nonabs_unregistered(self): @@ -83,7 +83,7 @@ class RenderTransformToResponseTests(unittest.TestCase, Base): self.assertEqual(result.app_iter, [resultstr]) self.assertEqual(result.status, '200 OK') self.assertEqual(len(result.headerlist), 2) - from repoze.bfg.template import XSLTemplateFactory + from repoze.bfg.xslt import XSLTemplateFactory self.failUnless(isinstance(queryUtility(INodeTemplate, minimal), XSLTemplateFactory)) @@ -91,7 +91,7 @@ class RenderTransformToResponseTests(unittest.TestCase, Base): self._zcmlConfigure() from zope.component import getGlobalSiteManager from zope.component import queryUtility - from repoze.bfg.template import XSLTemplateFactory + from repoze.bfg.xslt import XSLTemplateFactory from repoze.bfg.interfaces import INodeTemplate minimal = self._getTemplatePath('minimal.xsl') utility = XSLTemplateFactory(minimal) @@ -117,7 +117,7 @@ class RenderTransformTests(unittest.TestCase, Base): Base.tearDown(self) def _getFUT(self): - from repoze.bfg.template import render_transform + from repoze.bfg.xslt import render_transform return render_transform def test_nonabs_unregistered(self): @@ -133,7 +133,7 @@ class RenderTransformTests(unittest.TestCase, Base): self.failUnless(isinstance(result, str)) resultstr = """<?xml version="1.0"?>\n<div/>\n""" self.assertEqual(result, resultstr) - from repoze.bfg.template import XSLTemplateFactory + from repoze.bfg.xslt import XSLTemplateFactory self.failUnless(isinstance(queryUtility(INodeTemplate, minimal), XSLTemplateFactory)) @@ -141,7 +141,7 @@ class RenderTransformTests(unittest.TestCase, Base): self._zcmlConfigure() from zope.component import getGlobalSiteManager from zope.component import queryUtility - from repoze.bfg.template import XSLTemplateFactory + from repoze.bfg.xslt import XSLTemplateFactory from repoze.bfg.interfaces import INodeTemplate minimal = self._getTemplatePath('minimal.xsl') utility = XSLTemplateFactory(minimal) diff --git a/repoze/bfg/xslt.py b/repoze/bfg/xslt.py new file mode 100644 index 000000000..949bde6da --- /dev/null +++ b/repoze/bfg/xslt.py @@ -0,0 +1,85 @@ +import os + +from webob import Response + +from zope.component import queryUtility +from zope.component import getSiteManager +from zope.component.interfaces import ComponentLookupError + +from zope.interface import classProvides +from zope.interface import implements + +from repoze.bfg.path import caller_path + +from repoze.bfg.interfaces import INodeTemplate +from repoze.bfg.interfaces import ITemplateFactory + +def get_transform(path, node): + """ Return a callable transform object. When called, the + transform will return a string. The ``path`` argument should be a + package-relative path (also may be absolute) to an XSLT file. + When called, the transform will use the kwargs in ``*kw`` as top + level names and the lxml node at ``node``.""" + # Render using XSLT + path = caller_path(path) + + template = queryUtility(INodeTemplate, path) + if template is None: + if not os.path.exists(path): + raise ValueError('Missing template file: %s' % path) + template = XSLTemplateFactory(path) + try: + sm = getSiteManager() + except ComponentLookupError: + pass + else: + sm.registerUtility(template, INodeTemplate, name=path) + return template + +def render_transform(path, node, **kw): + """ Render a XSL template at the package-relative path (may also + be absolute) using the kwargs in ``*kw`` as top-level names and + the lxml node at ``node`` and return a string.""" + path = caller_path(path) + template = get_transform(path, node) + return template(node, **kw) + +def render_transform_to_response(path, node, **kw): + """ Render a XSL template at the package-relative path (may also + be absolute) using the kwargs in ``*kw`` as top-level names and + the lxml node at ``node`` and return a Response object.""" + path = caller_path(path) + result = render_transform(path, node, **kw) + return Response(result) + +class XSLTemplateFactory(object): + classProvides(ITemplateFactory) + implements(INodeTemplate) + + def __init__(self, path, auto_reload=False): + self.path = path + self.auto_reload = auto_reload + + def __call__(self, node, **kw): + processor = get_processor(self.path, self.auto_reload) + result = str(processor(node, **kw)) + return result + +# Manage XSLT processors on a per-thread basis +import threading +from lxml import etree +xslt_pool = threading.local() +def get_processor(xslt_fn, auto_reload=False): + if not auto_reload: + 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 diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py index a2a063603..b5de0584a 100644 --- a/repoze/bfg/zcml.py +++ b/repoze/bfg/zcml.py @@ -118,7 +118,7 @@ def zcml_configure(name, package, load=cPickle.load): try: vers, ptime, actions = load(open(pckname, 'rb')) except (IOError, cPickle.UnpicklingError, EOFError, TypeError, ValueError, - AttributeError, NameError): + AttributeError, NameError, ImportError): return file_configure(name, package) if vers != PVERSION: |
