From 3a97d1bd7a14815a503550c4deaccf2e0e300ceb Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 17 Nov 2008 20:17:08 +0000 Subject: - Add chameleon text template API (chameleon ${name} renderings where the template does not need to be wrapped in any containing XML). Prep for 0.4.9. --- repoze/bfg/chameleon_text.py | 85 ++++++++++++ repoze/bfg/tests/fixtures/minimal.txt | 1 + repoze/bfg/tests/fixtures/nonminimal.txt | 1 + repoze/bfg/tests/test_chameleon_text.py | 226 +++++++++++++++++++++++++++++++ 4 files changed, 313 insertions(+) create mode 100644 repoze/bfg/chameleon_text.py create mode 100644 repoze/bfg/tests/fixtures/minimal.txt create mode 100644 repoze/bfg/tests/fixtures/nonminimal.txt create mode 100644 repoze/bfg/tests/test_chameleon_text.py (limited to 'repoze') diff --git a/repoze/bfg/chameleon_text.py b/repoze/bfg/chameleon_text.py new file mode 100644 index 000000000..e00106e5c --- /dev/null +++ b/repoze/bfg/chameleon_text.py @@ -0,0 +1,85 @@ +from webob import Response + +from zope.component import queryUtility + +from zope.interface import classProvides +from zope.interface import implements + +from repoze.bfg.interfaces import ITemplateRenderer +from repoze.bfg.interfaces import ITemplateRendererFactory +from repoze.bfg.interfaces import ISettings + +from repoze.bfg.templating import renderer_from_cache + +from chameleon.core.template import TemplateFile +from chameleon.zpt.language import Parser + +class TextTemplateFile(TemplateFile): + default_parser = Parser() + + def __init__(self, filename, parser=None, format=None, + doctype=None, **kwargs): + if parser is None: + parser = self.default_parser + super(TextTemplateFile, self).__init__(filename, parser, format, + doctype, **kwargs) + +class TextTemplateRenderer(object): + classProvides(ITemplateRendererFactory) + implements(ITemplateRenderer) + + def __init__(self, path, auto_reload=False): + self.template = TextTemplateFile( + path, + format='text', + auto_reload=auto_reload + ) + + def implementation(self): + return self.template + + def __call__(self, **kw): + return self.template(**kw) + +def _auto_reload(): + settings = queryUtility(ISettings) + auto_reload = settings and settings.reload_templates + return auto_reload + +def get_renderer(path): + """ Return a callable ``ITemplateRenderer`` object representing a + ``chameleon`` text template at the package-relative path (may also + be absolute).""" + auto_reload = _auto_reload() + renderer = renderer_from_cache(path, TextTemplateRenderer, + auto_reload=auto_reload) + return renderer + +def get_template(path): + """ Return a ``chameleon`` text template at the package-relative + path (may also be absolute).""" + auto_reload = _auto_reload() + renderer = renderer_from_cache(path, TextTemplateRenderer, + auto_reload=auto_reload) + return renderer.implementation() + +def render_template(path, **kw): + """ Render a ``chameleon`` text template at the package-relative + path (may also be absolute) using the kwargs in ``*kw`` as + top-level names and return a string.""" + auto_reload = _auto_reload() + renderer = renderer_from_cache(path, TextTemplateRenderer, + auto_reload=auto_reload) + return renderer(**kw) + +def render_template_to_response(path, **kw): + """ Render a ``chameleon`` text template at the package-relative + path (may also be absolute) using the kwargs in ``*kw`` as + top-level names and return a Response object with the body as the + template result.""" + auto_reload = _auto_reload() + renderer = renderer_from_cache(path, TextTemplateRenderer, + auto_reload=auto_reload) + result = renderer(**kw) + return Response(result) + diff --git a/repoze/bfg/tests/fixtures/minimal.txt b/repoze/bfg/tests/fixtures/minimal.txt new file mode 100644 index 000000000..18832d351 --- /dev/null +++ b/repoze/bfg/tests/fixtures/minimal.txt @@ -0,0 +1 @@ +Hello. diff --git a/repoze/bfg/tests/fixtures/nonminimal.txt b/repoze/bfg/tests/fixtures/nonminimal.txt new file mode 100644 index 000000000..9de95ec92 --- /dev/null +++ b/repoze/bfg/tests/fixtures/nonminimal.txt @@ -0,0 +1 @@ +Hello, ${name}! diff --git a/repoze/bfg/tests/test_chameleon_text.py b/repoze/bfg/tests/test_chameleon_text.py new file mode 100644 index 000000000..8e53b7ff9 --- /dev/null +++ b/repoze/bfg/tests/test_chameleon_text.py @@ -0,0 +1,226 @@ +import unittest + +from zope.testing.cleanup import cleanUp + +class Base: + def setUp(self): + cleanUp() + + def tearDown(self): + cleanUp() + + 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 TextTemplateRendererTests(unittest.TestCase, Base): + def setUp(self): + Base.setUp(self) + + def tearDown(self): + Base.tearDown(self) + + def _getTargetClass(self): + from repoze.bfg.chameleon_text import TextTemplateRenderer + return TextTemplateRenderer + + 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 ITemplateRenderer + path = self._getTemplatePath('minimal.txt') + verifyObject(ITemplateRenderer, self._makeOne(path)) + + def test_class_implements_ITemplate(self): + from zope.interface.verify import verifyClass + from repoze.bfg.interfaces import ITemplateRenderer + verifyClass(ITemplateRenderer, self._getTargetClass()) + + def test_call(self): + self._zcmlConfigure() + minimal = self._getTemplatePath('minimal.txt') + instance = self._makeOne(minimal) + result = instance() + self.failUnless(isinstance(result, str)) + self.assertEqual(result, 'Hello.\n') + + def test_call_nonminimal(self): + self._zcmlConfigure() + nonminimal = self._getTemplatePath('nonminimal.txt') + instance = self._makeOne(nonminimal) + result = instance(name='Chris') + self.failUnless(isinstance(result, str)) + self.assertEqual(result, 'Hello, Chris!\n') + + def test_implementation(self): + self._zcmlConfigure() + minimal = self._getTemplatePath('minimal.txt') + instance = self._makeOne(minimal) + result = instance.implementation()() + self.failUnless(isinstance(result, str)) + self.assertEqual(result, 'Hello.\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_text import render_template + return render_template + + def test_it(self): + self._zcmlConfigure() + minimal = self._getTemplatePath('minimal.txt') + render = self._getFUT() + result = render(minimal) + self.failUnless(isinstance(result, str)) + self.assertEqual(result, 'Hello.\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_text import render_template_to_response + return render_template_to_response + + def test_minimal(self): + self._zcmlConfigure() + minimal = self._getTemplatePath('minimal.txt') + render = self._getFUT() + result = render(minimal) + from webob import Response + self.failUnless(isinstance(result, Response)) + self.assertEqual(result.app_iter, ['Hello.\n']) + self.assertEqual(result.status, '200 OK') + self.assertEqual(len(result.headerlist), 2) + +class GetRendererTests(unittest.TestCase, Base): + def setUp(self): + Base.setUp(self) + + def tearDown(self): + Base.tearDown(self) + + def _getFUT(self): + from repoze.bfg.chameleon_text import get_renderer + return get_renderer + + def test_nonabs_registered(self): + from zope.component import getGlobalSiteManager + from zope.component import queryUtility + from repoze.bfg.chameleon_text import TextTemplateRenderer + from repoze.bfg.interfaces import ITemplateRenderer + minimal = self._getTemplatePath('minimal.txt') + utility = TextTemplateRenderer(minimal) + gsm = getGlobalSiteManager() + gsm.registerUtility(utility, ITemplateRenderer, name=minimal) + get = self._getFUT() + result = get(minimal) + self.assertEqual(result, utility) + self.assertEqual(queryUtility(ITemplateRenderer, minimal), utility) + + def test_nonabs_unregistered(self): + from zope.component import getGlobalSiteManager + from zope.component import queryUtility + from repoze.bfg.chameleon_text import TextTemplateRenderer + from repoze.bfg.interfaces import ITemplateRenderer + minimal = self._getTemplatePath('minimal.txt') + self.assertEqual(queryUtility(ITemplateRenderer, minimal), None) + utility = TextTemplateRenderer(minimal) + gsm = getGlobalSiteManager() + gsm.registerUtility(utility, ITemplateRenderer, name=minimal) + get = self._getFUT() + result = get(minimal) + self.assertEqual(result, utility) + self.assertEqual(queryUtility(ITemplateRenderer, minimal), utility) + + def test_testing(self): + from zope.component import getGlobalSiteManager + from repoze.bfg.interfaces import ITestingTemplateRenderer + class Dummy: + template = object() + def implementation(self): + return self.template + gsm = getGlobalSiteManager() + utility = Dummy() + gsm.registerUtility(utility, ITestingTemplateRenderer, name='foo') + get = self._getFUT() + result = get('foo') + self.failUnless(result is utility) + +class GetTemplateTests(unittest.TestCase, Base): + def setUp(self): + Base.setUp(self) + + def tearDown(self): + Base.tearDown(self) + + def _getFUT(self): + from repoze.bfg.chameleon_text 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_text import TextTemplateRenderer + from repoze.bfg.interfaces import ITemplateRenderer + minimal = self._getTemplatePath('minimal.txt') + utility = TextTemplateRenderer(minimal) + gsm = getGlobalSiteManager() + gsm.registerUtility(utility, ITemplateRenderer, name=minimal) + get = self._getFUT() + result = get(minimal) + self.assertEqual(result.filename, minimal) + self.assertEqual(queryUtility(ITemplateRenderer, minimal), utility) + + def test_nonabs_unregistered(self): + self._zcmlConfigure() + from zope.component import getGlobalSiteManager + from zope.component import queryUtility + from repoze.bfg.chameleon_text import TextTemplateRenderer + from repoze.bfg.interfaces import ITemplateRenderer + minimal = self._getTemplatePath('minimal.txt') + self.assertEqual(queryUtility(ITemplateRenderer, minimal), None) + utility = TextTemplateRenderer(minimal) + gsm = getGlobalSiteManager() + gsm.registerUtility(utility, ITemplateRenderer, name=minimal) + get = self._getFUT() + result = get(minimal) + self.assertEqual(result.filename, minimal) + self.assertEqual(queryUtility(ITemplateRenderer, minimal), utility) + + def test_testing(self): + from zope.component import getGlobalSiteManager + from repoze.bfg.interfaces import ITestingTemplateRenderer + class Dummy: + template = object() + def implementation(self): + return self.template + gsm = getGlobalSiteManager() + utility = Dummy() + gsm.registerUtility(utility, ITestingTemplateRenderer, name='foo') + get = self._getFUT() + result = get('foo') + self.failUnless(result is utility.template) + + + + + -- cgit v1.2.3