From a9fed7675d8da572dee840676714b2653e3f7f79 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 16 Sep 2009 04:56:49 +0000 Subject: Checkpoint. Not 100% test coverage. --- repoze/bfg/chameleon_text.py | 61 +++++++---- repoze/bfg/chameleon_zpt.py | 46 ++++---- repoze/bfg/includes/configure.zcml | 16 ++- repoze/bfg/includes/meta.zcml | 6 +- repoze/bfg/interfaces.py | 23 ++-- repoze/bfg/renderers.py | 82 ++++++++++++++ repoze/bfg/templating.py | 95 ---------------- repoze/bfg/testing.py | 2 +- repoze/bfg/tests/test_chameleon_text.py | 4 +- repoze/bfg/tests/test_chameleon_zpt.py | 2 +- repoze/bfg/tests/test_renderers.py | 177 ++++++++++++++++++++++++++++++ repoze/bfg/tests/test_templating.py | 185 -------------------------------- repoze/bfg/tests/test_testing.py | 8 +- repoze/bfg/tests/test_view.py | 142 ++++++++++++++++++------ repoze/bfg/tests/test_zcml.py | 40 ++++--- repoze/bfg/view.py | 93 +++++++++------- repoze/bfg/zcml.py | 45 ++++---- 17 files changed, 571 insertions(+), 456 deletions(-) create mode 100644 repoze/bfg/renderers.py delete mode 100644 repoze/bfg/templating.py create mode 100644 repoze/bfg/tests/test_renderers.py delete mode 100644 repoze/bfg/tests/test_templating.py (limited to 'repoze') diff --git a/repoze/bfg/chameleon_text.py b/repoze/bfg/chameleon_text.py index f482d795f..1c9518b88 100644 --- a/repoze/bfg/chameleon_text.py +++ b/repoze/bfg/chameleon_text.py @@ -1,47 +1,68 @@ from webob import Response from zope.component import queryUtility +from zope.interface import implements from repoze.bfg.interfaces import IResponseFactory +from repoze.bfg.interfaces import ITemplateRenderer -from repoze.bfg.templating import renderer_from_cache -from repoze.bfg.templating import TextTemplateRenderer -from repoze.bfg.templating import _auto_reload +from chameleon.core.template import TemplateFile +from chameleon.zpt.language import Parser + +from repoze.bfg.renderers import template_renderer_factory +from repoze.bfg.settings import get_settings + +class TextTemplateFile(TemplateFile): + default_parser = Parser() + + def __init__(self, filename, parser=None, format='text', doctype=None, + **kwargs): + if parser is None: + parser = self.default_parser + super(TextTemplateFile, self).__init__(filename, parser, format, + doctype, **kwargs) + +def renderer_factory(path): + return template_renderer_factory(path, TextTemplateRenderer, level=4) + +class TextTemplateRenderer(object): + implements(ITemplateRenderer) + def __init__(self, path): + settings = get_settings() + auto_reload = settings and settings['reload_templates'] + self.template = TextTemplateFile(path, auto_reload=auto_reload) + + def implementation(self): + return self.template + + def __call__(self, kw): + return self.template(**kw) def get_renderer(path): """ Return a callable ``ITemplateRenderer`` object representing a - ``chameleon`` text template at the package-relative path (may also + ``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 + return renderer_factory(path) def get_template(path): - """ Return a ``chameleon`` text template at the package-relative + """ 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) + renderer = renderer_factory(path) 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) + renderer = renderer_factory(path) + 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) + renderer = renderer_factory(path) + result = renderer(kw) response_factory = queryUtility(IResponseFactory, default=Response) return response_factory(result) diff --git a/repoze/bfg/chameleon_zpt.py b/repoze/bfg/chameleon_zpt.py index c66a69e66..b4be1a4fc 100644 --- a/repoze/bfg/chameleon_zpt.py +++ b/repoze/bfg/chameleon_zpt.py @@ -1,65 +1,63 @@ from webob import Response from zope.component import queryUtility - -from zope.interface import classProvides from zope.interface import implements from repoze.bfg.interfaces import IResponseFactory from repoze.bfg.interfaces import ITemplateRenderer -from repoze.bfg.interfaces import ITemplateRendererFactory -from repoze.bfg.templating import renderer_from_cache -from repoze.bfg.templating import _auto_reload from chameleon.zpt.template import PageTemplateFile +from repoze.bfg.renderers import template_renderer_factory +from repoze.bfg.settings import get_settings + +def renderer_factory(path, level=4): + return template_renderer_factory(path, ZPTTemplateRenderer, level=4) + class ZPTTemplateRenderer(object): - classProvides(ITemplateRendererFactory) implements(ITemplateRenderer) - - def __init__(self, path, auto_reload=False): + def __init__(self, path): + settings = get_settings() + auto_reload = settings and settings['reload_templates'] self.template = PageTemplateFile(path, auto_reload=auto_reload) def implementation(self): return self.template - def __call__(self, **kw): + def __call__(self, kw): return self.template(**kw) def get_renderer(path): """ Return a callable ``ITemplateRenderer`` object representing a ``chameleon.zpt`` template at the package-relative path (may also be absolute). """ - auto_reload = _auto_reload() - renderer = renderer_from_cache(path, ZPTTemplateRenderer, - auto_reload=auto_reload) - return renderer + return renderer_factory(path) def get_template(path): """ Return a ``chameleon.zpt`` template at the package-relative path (may also be absolute). """ - auto_reload = _auto_reload() - renderer = renderer_from_cache(path, ZPTTemplateRenderer, - auto_reload=auto_reload) + renderer = renderer_factory(path) return renderer.implementation() 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.""" - auto_reload = _auto_reload() - renderer = renderer_from_cache(path, ZPTTemplateRenderer, - auto_reload=auto_reload) - return renderer(**kw) + renderer = renderer_factory(path) + return renderer(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 with the body as the template result. """ - auto_reload = _auto_reload() - renderer = renderer_from_cache(path, ZPTTemplateRenderer, - auto_reload=auto_reload) - result = renderer(**kw) + renderer = renderer_factory(path) + result = renderer(kw) response_factory = queryUtility(IResponseFactory, default=Response) return response_factory(result) + +def _auto_reload(): + settings = get_settings() + if settings: + return settings['reload_templates'] + return False diff --git a/repoze/bfg/includes/configure.zcml b/repoze/bfg/includes/configure.zcml index be8a69543..37cd4d75a 100644 --- a/repoze/bfg/includes/configure.zcml +++ b/repoze/bfg/includes/configure.zcml @@ -18,9 +18,19 @@ for="* repoze.bfg.interfaces.IRequest" /> - + + + + diff --git a/repoze/bfg/includes/meta.zcml b/repoze/bfg/includes/meta.zcml index 8195101be..2eeb87314 100644 --- a/repoze/bfg/includes/meta.zcml +++ b/repoze/bfg/includes/meta.zcml @@ -71,9 +71,9 @@ /> diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py index 827654b1d..928ee6c54 100644 --- a/repoze/bfg/interfaces.py +++ b/repoze/bfg/interfaces.py @@ -74,21 +74,26 @@ class ITraverserFactory(Interface): def __call__(context): """ Return an object that implements ITraverser """ -class ITemplateRenderer(Interface): +class IRenderer(Interface): + def __call__(value): + """ Call a the renderer implementation with the result of the + view (``value``) passed in and return a result (a string or + unicode object useful as a response body)""" + +class IRendererFactory(Interface): + def __call__(name): + """ Return an object that implements ``IRenderer`` """ + +class ITemplateRenderer(IRenderer): def implementation(): """ Return the object that the underlying templating system uses to render the template; it is typically a callable that accepts arbitrary keyword arguments and returns a string or unicode object """ - def __call__(**kw): - """ Call a the template implementation with the keywords - passed in as arguments and return the result (a string or - unicode object) """ - -class ITemplateRendererFactory(Interface): - def __call__(path, auto_reload=False): - """ Return an object that implements ``ITemplateRenderer`` """ +class ITemplateRendererFactory(IRendererFactory): + def __call__(path): + """ Return an object that implements ``ITemplateRenderer`` """ class IViewPermission(Interface): def __call__(context, request): diff --git a/repoze/bfg/renderers.py b/repoze/bfg/renderers.py new file mode 100644 index 000000000..495a35541 --- /dev/null +++ b/repoze/bfg/renderers.py @@ -0,0 +1,82 @@ +import os +import pkg_resources + +from zope.component import queryUtility +from zope.component import getSiteManager + +from repoze.bfg.path import caller_package +from repoze.bfg.settings import get_settings + +from repoze.bfg.interfaces import IRendererFactory +from repoze.bfg.interfaces import ITemplateRenderer + +try: + import json +except ImportError: + import simplejson as json + +# concrete renderer factory implementations + +def json_renderer_factory(name): + def _render(value): + return json.dumps(value) + return _render + +# utility functions + +def template_renderer_factory(path, impl, level=3): + if os.path.isabs(path): + # 'path' is an absolute filename (not common and largely only + # for backwards compatibility) + if not os.path.exists(path): + raise ValueError('Missing template file: %s' % path) + renderer = queryUtility(ITemplateRenderer, name=path) + if renderer is None: + renderer = impl(path) + sm = getSiteManager() + sm.registerUtility(renderer, ITemplateRenderer, name=path) + + else: + # 'path' is a relative filename or a package:relpath spec + if ':' in path: + # it's a package:relpath spec + spec = path.split(':', 1) + utility_name = path + else: + # it's a relpath only + package = caller_package(level=level) + spec = (package.__name__, path) + utility_name = '%s:%s' % spec # utility name must be a string + renderer = queryUtility(ITemplateRenderer, name=utility_name) + if renderer is None: + # service unit tests here by trying the relative path + # string as the utility name directly + renderer = queryUtility(ITemplateRenderer, name=path) + if renderer is None: + if not pkg_resources.resource_exists(*spec): + raise ValueError('Missing template resource: %s' % utility_name) + abspath = pkg_resources.resource_filename(*spec) + renderer = impl(abspath) + if not _reload_resources(): + # cache the template + sm = getSiteManager() + sm.registerUtility(renderer, ITemplateRenderer, + name=utility_name) + + return renderer + +def renderer_from_name(path, level=4): + name = os.path.splitext(path)[1] + if not name: + name = path + factory = queryUtility(IRendererFactory, name=name) + if factory is None: + raise ValueError('No renderer for renderer name %r' % name) + return factory(path) + +def _reload_resources(): + settings = get_settings() + if settings: + return settings['reload_resources'] + return False + diff --git a/repoze/bfg/templating.py b/repoze/bfg/templating.py deleted file mode 100644 index 2ec049ca5..000000000 --- a/repoze/bfg/templating.py +++ /dev/null @@ -1,95 +0,0 @@ -import os -import pkg_resources - -from zope.component import queryUtility -from zope.component import getSiteManager - -from zope.interface import classProvides -from zope.interface import implements - -from chameleon.core.template import TemplateFile -from chameleon.zpt.language import Parser - -from repoze.bfg.interfaces import ISettings -from repoze.bfg.interfaces import ITemplateRenderer -from repoze.bfg.interfaces import ITemplateRendererFactory -from repoze.bfg.path import caller_package -from repoze.bfg.settings import get_settings - -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 renderer_from_cache(path, factory, level=3, **kw): - if os.path.isabs(path): - # 'path' is an absolute filename (not common and largely only - # for backwards compatibility) - if not os.path.exists(path): - raise ValueError('Missing template file: %s' % path) - renderer = queryUtility(ITemplateRenderer, name=path) - if renderer is None: - renderer = factory(path, **kw) - sm = getSiteManager() - sm.registerUtility(renderer, ITemplateRenderer, name=path) - - else: - # 'path' is a relative filename or a package:relpath spec - if ':' in path: - # it's a package:relpath spec - spec = path.split(':', 1) - utility_name = path - else: - # it's a relpath only - package = caller_package(level=level) - spec = (package.__name__, path) - utility_name = '%s:%s' % spec # utility name must be a string - renderer = queryUtility(ITemplateRenderer, name=utility_name) - if renderer is None: - # service unit tests here by trying the relative path - # string as the utility name directly - renderer = queryUtility(ITemplateRenderer, name=path) - if renderer is None: - if not pkg_resources.resource_exists(*spec): - raise ValueError('Missing template resource: %s' % utility_name) - abspath = pkg_resources.resource_filename(*spec) - renderer = factory(abspath, **kw) - settings = get_settings() - if (not settings) or (not settings.get('reload_resources')): - # cache the template - sm = getSiteManager() - sm.registerUtility(renderer, ITemplateRenderer, - name=utility_name) - - return renderer - -def renderer_from_path(path, level=4, **kw): - extension = os.path.splitext(path)[1] - factory = queryUtility(ITemplateRendererFactory, name=extension, - default=TextTemplateRenderer) - return renderer_from_cache(path, factory, level, **kw) - -def _auto_reload(): - settings = queryUtility(ISettings) - auto_reload = settings and settings['reload_templates'] - return auto_reload - diff --git a/repoze/bfg/testing.py b/repoze/bfg/testing.py index 1c9dad9e0..8fbeb6012 100644 --- a/repoze/bfg/testing.py +++ b/repoze/bfg/testing.py @@ -264,7 +264,7 @@ class DummyTemplateRenderer: def implementation(self): return self - def __call__(self, **kw): + def __call__(self, kw): self._received.update(kw) return self.string_response diff --git a/repoze/bfg/tests/test_chameleon_text.py b/repoze/bfg/tests/test_chameleon_text.py index 139a77072..ddb6f717a 100644 --- a/repoze/bfg/tests/test_chameleon_text.py +++ b/repoze/bfg/tests/test_chameleon_text.py @@ -51,7 +51,7 @@ class TextTemplateRendererTests(Base, unittest.TestCase): self._zcmlConfigure() minimal = self._getTemplatePath('minimal.txt') instance = self._makeOne(minimal) - result = instance() + result = instance({}) self.failUnless(isinstance(result, str)) self.assertEqual(result, 'Hello.\n') @@ -59,7 +59,7 @@ class TextTemplateRendererTests(Base, unittest.TestCase): self._zcmlConfigure() nonminimal = self._getTemplatePath('nonminimal.txt') instance = self._makeOne(nonminimal) - result = instance(name='Chris') + result = instance({'name':'Chris'}) self.failUnless(isinstance(result, str)) self.assertEqual(result, 'Hello, Chris!\n') diff --git a/repoze/bfg/tests/test_chameleon_zpt.py b/repoze/bfg/tests/test_chameleon_zpt.py index 4a1cac166..f6d7c0da5 100644 --- a/repoze/bfg/tests/test_chameleon_zpt.py +++ b/repoze/bfg/tests/test_chameleon_zpt.py @@ -44,7 +44,7 @@ class ZPTTemplateRendererTests(Base, unittest.TestCase): self._zcmlConfigure() minimal = self._getTemplatePath('minimal.pt') instance = self._makeOne(minimal) - result = instance() + result = instance({}) self.failUnless(isinstance(result, unicode)) self.assertEqual(result, '
\n
') diff --git a/repoze/bfg/tests/test_renderers.py b/repoze/bfg/tests/test_renderers.py new file mode 100644 index 000000000..aa159cc18 --- /dev/null +++ b/repoze/bfg/tests/test_renderers.py @@ -0,0 +1,177 @@ +import unittest + +from repoze.bfg.testing import cleanUp +from repoze.bfg import testing + +class TestTemplateRendererFactory(unittest.TestCase): + def setUp(self): + cleanUp() + + def tearDown(self): + cleanUp() + + def _callFUT(self, path, factory, level=3): + from repoze.bfg.renderers import template_renderer_factory + return template_renderer_factory(path, factory, level) + + def test_abspath_notfound(self): + from repoze.bfg.interfaces import ITemplateRenderer + abspath = '/wont/exist' + testing.registerUtility({}, ITemplateRenderer, name=abspath) + self.assertRaises(ValueError, self._callFUT, abspath, None) + + def test_abspath_alreadyregistered(self): + from repoze.bfg.interfaces import ITemplateRenderer + import os + abspath = os.path.abspath(__file__) + renderer = {} + testing.registerUtility(renderer, ITemplateRenderer, name=abspath) + result = self._callFUT(abspath, None) + self.failUnless(result is renderer) + + def test_abspath_notyetregistered(self): + from repoze.bfg.interfaces import ITemplateRenderer + import os + abspath = os.path.abspath(__file__) + renderer = {} + testing.registerUtility(renderer, ITemplateRenderer, name=abspath) + result = self._callFUT(abspath, None) + self.failUnless(result is renderer) + + def test_relpath_path_registered(self): + renderer = {} + from repoze.bfg.interfaces import ITemplateRenderer + testing.registerUtility(renderer, ITemplateRenderer, name='foo/bar') + result = self._callFUT('foo/bar', None) + self.failUnless(renderer is result) + + def test_relpath_is_package_registered(self): + renderer = {} + from repoze.bfg.interfaces import ITemplateRenderer + testing.registerUtility(renderer, ITemplateRenderer, name='foo:bar/baz') + result = self._callFUT('foo:bar/baz', None) + self.failUnless(renderer is result) + + def test_relpath_notfound(self): + self.assertRaises(ValueError, self._callFUT, 'wont/exist', None) + + def test_relpath_is_package_notfound(self): + from repoze.bfg import tests + module_name = tests.__name__ + self.assertRaises(ValueError, self._callFUT, + '%s:wont/exist' % module_name, None) + + def test_relpath_alreadyregistered(self): + from repoze.bfg.interfaces import ITemplateRenderer + from repoze.bfg import tests + module_name = tests.__name__ + relpath = 'test_templating.py' + spec = '%s:%s' % (module_name, relpath) + renderer = {} + testing.registerUtility(renderer, ITemplateRenderer, name=spec) + result = self._callFUT('test_templating.py', None) + self.failUnless(result is renderer) + + def test_relpath_is_package_alreadyregistered(self): + from repoze.bfg.interfaces import ITemplateRenderer + from repoze.bfg import tests + module_name = tests.__name__ + relpath = 'test_templating.py' + spec = '%s:%s' % (module_name, relpath) + renderer = {} + testing.registerUtility(renderer, ITemplateRenderer, name=spec) + result = self._callFUT(spec, None) + self.failUnless(result is renderer) + + def test_relpath_notyetregistered(self): + import os + from repoze.bfg.tests import test_templating + module_name = test_templating.__name__ + relpath = 'test_renderers.py' + renderer = {} + factory = DummyFactory(renderer) + result = self._callFUT('test_renderers.py', factory) + self.failUnless(result is renderer) + path = os.path.abspath(__file__) + if path.endswith('pyc'): # pragma: no cover + path = path[:-1] + self.assertEqual(factory.path, path) + self.assertEqual(factory.kw, {}) + + def test_relpath_is_package_notyetregistered(self): + import os + from repoze.bfg import tests + module_name = tests.__name__ + relpath = 'test_renderers.py' + renderer = {} + factory = DummyFactory(renderer) + spec = '%s:%s' % (module_name, relpath) + result = self._callFUT(spec, factory) + self.failUnless(result is renderer) + path = os.path.abspath(__file__) + if path.endswith('pyc'): # pragma: no cover + path = path[:-1] + self.assertEqual(factory.path, path) + self.assertEqual(factory.kw, {}) + + def test_reload_resources_true(self): + from zope.component import queryUtility + from repoze.bfg.interfaces import ISettings + from repoze.bfg.interfaces import ITemplateRenderer + settings = {'reload_resources':True} + testing.registerUtility(settings, ISettings) + renderer = {} + factory = DummyFactory(renderer) + result = self._callFUT('test_renderers.py', factory) + self.failUnless(result is renderer) + spec = '%s:%s' % ('repoze.bfg.tests', 'test_renderers.py') + self.assertEqual(queryUtility(ITemplateRenderer, name=spec), + None) + + def test_reload_resources_false(self): + from zope.component import queryUtility + from repoze.bfg.interfaces import ISettings + from repoze.bfg.interfaces import ITemplateRenderer + settings = {'reload_resources':False} + testing.registerUtility(settings, ISettings) + renderer = {} + factory = DummyFactory(renderer) + result = self._callFUT('test_renderers.py', factory) + self.failUnless(result is renderer) + spec = '%s:%s' % ('repoze.bfg.tests', 'test_renderers.py') + self.assertNotEqual(queryUtility(ITemplateRenderer, name=spec), + None) + +class TestRendererFromPath(unittest.TestCase): + def setUp(self): + cleanUp() + + def tearDown(self): + cleanUp() + + def _callFUT(self, path, level=4): + from repoze.bfg.renderers import renderer_from_name + return renderer_from_name(path, level) + + def test_it(self): + from repoze.bfg.interfaces import ITemplateRendererFactory + import os + here = os.path.dirname(os.path.abspath(__file__)) + fixture = os.path.join(here, 'fixtures/minimal.pt') + renderer = {} + def factory(path, **kw): + return renderer + testing.registerUtility(factory, ITemplateRendererFactory, name='.pt') + result = self._callFUT(fixture) + self.assertEqual(result, renderer) + +class DummyFactory: + def __init__(self, renderer): + self.renderer = renderer + + def __call__(self, path, **kw): + self.path = path + self.kw = kw + return self.renderer + + diff --git a/repoze/bfg/tests/test_templating.py b/repoze/bfg/tests/test_templating.py deleted file mode 100644 index c3894cce4..000000000 --- a/repoze/bfg/tests/test_templating.py +++ /dev/null @@ -1,185 +0,0 @@ -import unittest - -from repoze.bfg.testing import cleanUp -from repoze.bfg import testing - -class TestRendererFromCache(unittest.TestCase): - def setUp(self): - cleanUp() - - def tearDown(self): - cleanUp() - - def _callFUT(self, path, factory, level=3, **kw): - from repoze.bfg.templating import renderer_from_cache - return renderer_from_cache(path, factory, level, **kw) - - def test_abspath_notfound(self): - from repoze.bfg.interfaces import ITemplateRenderer - abspath = '/wont/exist' - testing.registerUtility({}, ITemplateRenderer, name=abspath) - self.assertRaises(ValueError, self._callFUT, abspath, None) - - def test_abspath_alreadyregistered(self): - from repoze.bfg.interfaces import ITemplateRenderer - import os - abspath = os.path.abspath(__file__) - renderer = {} - testing.registerUtility(renderer, ITemplateRenderer, name=abspath) - result = self._callFUT(abspath, None) - self.failUnless(result is renderer) - - def test_abspath_notyetregistered(self): - from repoze.bfg.interfaces import ITemplateRenderer - import os - abspath = os.path.abspath(__file__) - renderer = {} - testing.registerUtility(renderer, ITemplateRenderer, name=abspath) - result = self._callFUT(abspath, None) - self.failUnless(result is renderer) - - def test_relpath_path_registered(self): - renderer = {} - from repoze.bfg.interfaces import ITemplateRenderer - testing.registerUtility(renderer, ITemplateRenderer, name='foo/bar') - result = self._callFUT('foo/bar', None) - self.failUnless(renderer is result) - - def test_relpath_is_package_registered(self): - renderer = {} - from repoze.bfg.interfaces import ITemplateRenderer - testing.registerUtility(renderer, ITemplateRenderer, name='foo:bar/baz') - result = self._callFUT('foo:bar/baz', None) - self.failUnless(renderer is result) - - def test_relpath_notfound(self): - self.assertRaises(ValueError, self._callFUT, 'wont/exist', None) - - def test_relpath_is_package_notfound(self): - from repoze.bfg import tests - module_name = tests.__name__ - self.assertRaises(ValueError, self._callFUT, - '%s:wont/exist' % module_name, None) - - def test_relpath_alreadyregistered(self): - from repoze.bfg.interfaces import ITemplateRenderer - from repoze.bfg import tests - module_name = tests.__name__ - relpath = 'test_templating.py' - spec = '%s:%s' % (module_name, relpath) - renderer = {} - testing.registerUtility(renderer, ITemplateRenderer, name=spec) - result = self._callFUT('test_templating.py', None) - self.failUnless(result is renderer) - - def test_relpath_is_package_alreadyregistered(self): - from repoze.bfg.interfaces import ITemplateRenderer - from repoze.bfg import tests - module_name = tests.__name__ - relpath = 'test_templating.py' - spec = '%s:%s' % (module_name, relpath) - renderer = {} - testing.registerUtility(renderer, ITemplateRenderer, name=spec) - result = self._callFUT(spec, None) - self.failUnless(result is renderer) - - def test_relpath_notyetregistered(self): - import os - from repoze.bfg.tests import test_templating - module_name = test_templating.__name__ - relpath = 'test_templating.py' - renderer = {} - factory = DummyFactory(renderer) - result = self._callFUT('test_templating.py', factory) - self.failUnless(result is renderer) - path = os.path.abspath(__file__) - if path.endswith('pyc'): # pragma: no cover - path = path[:-1] - self.assertEqual(factory.path, path) - self.assertEqual(factory.kw, {}) - - def test_relpath_is_package_notyetregistered(self): - import os - from repoze.bfg import tests - module_name = tests.__name__ - relpath = 'test_templating.py' - renderer = {} - factory = DummyFactory(renderer) - spec = '%s:%s' % (module_name, relpath) - result = self._callFUT(spec, factory) - self.failUnless(result is renderer) - path = os.path.abspath(__file__) - if path.endswith('pyc'): # pragma: no cover - path = path[:-1] - self.assertEqual(factory.path, path) - self.assertEqual(factory.kw, {}) - - def test_reload_resources_true(self): - from zope.component import queryUtility - from repoze.bfg.interfaces import ISettings - from repoze.bfg.interfaces import ITemplateRenderer - settings = {'reload_resources':True} - testing.registerUtility(settings, ISettings) - renderer = {} - factory = DummyFactory(renderer) - result = self._callFUT('test_templating.py', factory) - self.failUnless(result is renderer) - spec = '%s:%s' % ('repoze.bfg.tests', 'test_templating.py') - self.assertEqual(queryUtility(ITemplateRenderer, name=spec), - None) - - def test_reload_resources_false(self): - from zope.component import queryUtility - from repoze.bfg.interfaces import ISettings - from repoze.bfg.interfaces import ITemplateRenderer - settings = {'reload_resources':False} - testing.registerUtility(settings, ISettings) - renderer = {} - factory = DummyFactory(renderer) - result = self._callFUT('test_templating.py', factory) - self.failUnless(result is renderer) - spec = '%s:%s' % ('repoze.bfg.tests', 'test_templating.py') - self.assertNotEqual(queryUtility(ITemplateRenderer, name=spec), - None) - -class TestRendererFromPath(unittest.TestCase): - def setUp(self): - cleanUp() - - def tearDown(self): - cleanUp() - - def _callFUT(self, path, level=4, **kw): - from repoze.bfg.templating import renderer_from_path - return renderer_from_path(path, level, **kw) - - def test_with_default(self): - from repoze.bfg.templating import TextTemplateRenderer - import os - here = os.path.dirname(os.path.abspath(__file__)) - fixture = os.path.join(here, 'fixtures/minimal.txt') - result = self._callFUT(fixture) - self.assertEqual(result.__class__, TextTemplateRenderer) - - def test_with_nondefault(self): - from repoze.bfg.interfaces import ITemplateRendererFactory - import os - here = os.path.dirname(os.path.abspath(__file__)) - fixture = os.path.join(here, 'fixtures/minimal.pt') - renderer = {} - def factory(path, **kw): - return renderer - testing.registerUtility(factory, ITemplateRendererFactory, name='.pt') - result = self._callFUT(fixture) - self.assertEqual(result, renderer) - -class DummyFactory: - def __init__(self, renderer): - self.renderer = renderer - - def __call__(self, path, **kw): - self.path = path - self.kw = kw - return self.renderer - - diff --git a/repoze/bfg/tests/test_testing.py b/repoze/bfg/tests/test_testing.py index e81a90219..9ebd8468a 100644 --- a/repoze/bfg/tests/test_testing.py +++ b/repoze/bfg/tests/test_testing.py @@ -65,7 +65,7 @@ class TestTestingFunctions(unittest.TestCase): def test_registerDummyRenderer_explicitrenderer(self): from repoze.bfg import testing - def renderer(**kw): + def renderer(kw): raise ValueError renderer = testing.registerDummyRenderer('templates/foo', renderer) from repoze.bfg.chameleon_zpt import render_template_to_response @@ -460,20 +460,20 @@ class TestDummyTemplateRenderer(unittest.TestCase): def test_getattr(self): renderer = self._makeOne() - renderer(a=1) + renderer({'a':1}) self.assertEqual(renderer.a, 1) self.assertRaises(AttributeError, renderer.__getattr__, 'b') def test_assert_(self): renderer = self._makeOne() - renderer(a=1, b=2) + renderer({'a':1, 'b':2}) self.assertRaises(AssertionError, renderer.assert_, c=1) self.assertRaises(AssertionError, renderer.assert_, b=3) self.failUnless(renderer.assert_(a=1, b=2)) def test_nondefault_string_response(self): renderer = self._makeOne('abc') - result = renderer(a=1, b=2) + result = renderer({'a':1, 'b':2}) self.assertEqual(result, 'abc') class CleanUpTests(object): diff --git a/repoze/bfg/tests/test_view.py b/repoze/bfg/tests/test_view.py index 5639e9799..3106359a3 100644 --- a/repoze/bfg/tests/test_view.py +++ b/repoze/bfg/tests/test_view.py @@ -631,6 +631,25 @@ class Test_map_view(unittest.TestCase): from repoze.bfg.view import map_view return map_view(view, *arg, **kw) + def _registerRenderer(self): + from repoze.bfg.interfaces import IRendererFactory + from repoze.bfg.interfaces import ITemplateRenderer + from zope.interface import implements + from zope.component import getSiteManager + class Renderer: + implements(ITemplateRenderer) + def __call__(self, *arg): + return 'Hello!' + + class RendererFactory: + def __call__(self, path): + self.path = path + return Renderer() + + factory = RendererFactory() + sm = getSiteManager() + sm.registerUtility(factory, IRendererFactory, name='.txt') + def test_view_as_function_context_and_request(self): def view(context, request): return 'OK' @@ -646,10 +665,11 @@ class Test_map_view(unittest.TestCase): self.assertRaises(TypeError, result, None, None) def test_view_as_function_with_attr_and_template(self): + self._registerRenderer() def view(context, request): """ """ result = self._callFUT(view, attr='__name__', - template='fixtures/minimal.txt') + renderer='fixtures/minimal.txt') self.failIf(result is view) self.assertRaises(TypeError, result, None, None) @@ -701,18 +721,20 @@ class Test_map_view(unittest.TestCase): def test_view_as_newstyle_class_context_and_request_with_attr_and_template( self): + self._registerRenderer() class view(object): def __init__(self, context, request): pass def index(self): return {'a':'1'} result = self._callFUT(view, attr='index', - template='repoze.bfg.tests:fixtures/minimal.txt') + renderer='repoze.bfg.tests:fixtures/minimal.txt') self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result(None, None).body, 'Hello.\n') + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') def test_view_as_newstyle_class_requestonly(self): class view(object): @@ -741,18 +763,20 @@ class Test_map_view(unittest.TestCase): self.assertEqual(result(None, None), 'OK') def test_view_as_newstyle_class_requestonly_with_attr_and_template(self): + self._registerRenderer() class view(object): def __init__(self, request): pass def index(self): return {'a':'1'} result = self._callFUT(view, attr='index', - template='repoze.bfg.tests:fixtures/minimal.txt') + renderer='repoze.bfg.tests:fixtures/minimal.txt') self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result(None, None).body, 'Hello.\n') + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') def test_view_as_oldstyle_class_context_and_request(self): class view: @@ -782,18 +806,20 @@ class Test_map_view(unittest.TestCase): def test_view_as_oldstyle_class_context_and_request_with_attr_and_template( self): + self._registerRenderer() class view: def __init__(self, context, request): pass def index(self): return {'a':'1'} result = self._callFUT(view, attr='index', - template='repoze.bfg.tests:fixtures/minimal.txt') + renderer='repoze.bfg.tests:fixtures/minimal.txt') self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result(None, None).body, 'Hello.\n') + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') def test_view_as_oldstyle_class_requestonly(self): class view: @@ -822,18 +848,20 @@ class Test_map_view(unittest.TestCase): self.assertEqual(result(None, None), 'OK') def test_view_as_oldstyle_class_requestonly_with_attr_and_template(self): + self._registerRenderer() class view: def __init__(self, request): pass def index(self): return {'a':'1'} result = self._callFUT(view, attr='index', - template='repoze.bfg.tests:fixtures/minimal.txt') + renderer='repoze.bfg.tests:fixtures/minimal.txt') self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result(None, None).body, 'Hello.\n') + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') def test_view_as_instance_context_and_request(self): class View: @@ -854,14 +882,16 @@ class Test_map_view(unittest.TestCase): self.assertEqual(result(None, None), 'OK') def test_view_as_instance_context_and_request_attr_and_template(self): + self._registerRenderer() class View: def index(self, context, request): return {'a':'1'} view = View() result = self._callFUT(view, attr='index', - template='repoze.bfg.tests:fixtures/minimal.txt') + renderer='repoze.bfg.tests:fixtures/minimal.txt') self.failIf(result is view) - self.assertEqual(result(None, None).body, 'Hello.\n') + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') def test_view_as_instance_requestonly(self): class View: @@ -888,27 +918,31 @@ class Test_map_view(unittest.TestCase): self.assertEqual(result(None, None), 'OK') def test_view_as_instance_requestonly_with_attr_and_template(self): + self._registerRenderer() class View: def index(self, request): return {'a':'1'} view = View() result = self._callFUT(view, attr='index', - template='repoze.bfg.tests:fixtures/minimal.txt') + renderer='repoze.bfg.tests:fixtures/minimal.txt') self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) self.failUnless('instance' in result.__name__) - self.assertEqual(result(None, None).body, 'Hello.\n') + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') def test_view_templateonly(self): + self._registerRenderer() def view(context, request): return {'a':'1'} result = self._callFUT(view, - template='repoze.bfg.tests:fixtures/minimal.txt') + renderer='repoze.bfg.tests:fixtures/minimal.txt') self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(result(None, None).body, 'Hello.\n') + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') class TestRequestOnly(unittest.TestCase): def _callFUT(self, arg): @@ -1112,7 +1146,7 @@ class TestDecorateView(unittest.TestCase): self.failUnless(view1.__predicated__.im_func is view2.__predicated__.im_func) -class Test_templated_response(unittest.TestCase): +class Test_rendered_response(unittest.TestCase): def setUp(self): cleanUp() @@ -1120,61 +1154,105 @@ class Test_templated_response(unittest.TestCase): cleanUp() def _callFUT(self, template_name, response, view=None, - context=None, request=None, auto_reload=False): - from repoze.bfg.view import templated_response - return templated_response(template_name, response, view, context, - request, auto_reload) + context=None, request=None): + from repoze.bfg.view import rendered_response + if request is None: + request = DummyRequest() + return rendered_response(template_name, response, view, context, + request) + + def _registerRenderer(self): + from repoze.bfg.interfaces import IRendererFactory + from repoze.bfg.interfaces import ITemplateRenderer + from zope.interface import implements + from zope.component import getSiteManager + class Renderer: + implements(ITemplateRenderer) + def __call__(self, *arg): + return 'Hello!' + + class RendererFactory: + def __call__(self, path): + self.path = path + return Renderer() + + factory = RendererFactory() + sm = getSiteManager() + sm.registerUtility(factory, IRendererFactory, name='.txt') def test_is_response(self): + self._registerRenderer() response = DummyResponse() result = self._callFUT( 'repoze.bfg.tests:fixtures/minimal.txt', response) self.assertEqual(result, response) def test_is_not_valid_dict(self): + self._registerRenderer() response = None result = self._callFUT( 'repoze.bfg.tests:fixtures/minimal.txt', response) self.assertEqual(result, response) def test_valid_dict(self): + self._registerRenderer() response = {'a':'1'} result = self._callFUT( 'repoze.bfg.tests:fixtures/minimal.txt', response) - self.assertEqual(result.body, 'Hello.\n') + self.assertEqual(result.body, 'Hello!') def test_with_content_type(self): - response = {'a':'1', 'content_type_':'text/nonsense'} + self._registerRenderer() + response = {'a':'1'} + request = DummyRequest() + attrs = {'response_content_type':'text/nonsense'} + request.environ['webob.adhoc_attrs'] = attrs result = self._callFUT( - 'repoze.bfg.tests:fixtures/minimal.txt', response) + 'repoze.bfg.tests:fixtures/minimal.txt', response, request=request) self.assertEqual(result.content_type, 'text/nonsense') def test_with_headerlist(self): - response = {'a':'1', 'headerlist_':[('a', '1'), ('b', '2')]} + self._registerRenderer() + response = {'a':'1'} + request = DummyRequest() + attrs = {'response_headerlist':[('a', '1'), ('b', '2')]} + request.environ['webob.adhoc_attrs'] = attrs result = self._callFUT( - 'repoze.bfg.tests:fixtures/minimal.txt', response) + 'repoze.bfg.tests:fixtures/minimal.txt', response, request=request) self.assertEqual(result.headerlist, [('Content-Type', 'text/html; charset=UTF-8'), - ('Content-Length', '7'), + ('Content-Length', '6'), ('a', '1'), ('b', '2')]) def test_with_status(self): - response = {'a':'1', 'status_':'406 You Lose'} + self._registerRenderer() + response = {'a':'1'} + request = DummyRequest() + attrs = {'response_status':'406 You Lose'} + request.environ['webob.adhoc_attrs'] = attrs result = self._callFUT( - 'repoze.bfg.tests:fixtures/minimal.txt', response) + 'repoze.bfg.tests:fixtures/minimal.txt', response, request=request) self.assertEqual(result.status, '406 You Lose') def test_with_charset(self): - response = {'a':'1', 'charset_':'UTF-16'} + self._registerRenderer() + response = {'a':'1'} + request = DummyRequest() + attrs = {'response_charset':'UTF-16'} + request.environ['webob.adhoc_attrs'] = attrs result = self._callFUT( - 'repoze.bfg.tests:fixtures/minimal.txt', response) + 'repoze.bfg.tests:fixtures/minimal.txt', response, request=request) self.assertEqual(result.charset, 'UTF-16') def test_with_cache_for(self): - response = {'a':'1', 'cache_for_':100} + self._registerRenderer() + response = {'a':'1'} + request = DummyRequest() + attrs = {'response_cache_for':100} + request.environ['webob.adhoc_attrs'] = attrs result = self._callFUT( - 'repoze.bfg.tests:fixtures/minimal.txt', response) + 'repoze.bfg.tests:fixtures/minimal.txt', response, request=request) self.assertEqual(result.cache_control.max_age, 100) class DummyContext: diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py index 208e8e754..21d55504d 100644 --- a/repoze/bfg/tests/test_zcml.py +++ b/repoze/bfg/tests/test_zcml.py @@ -320,8 +320,7 @@ class TestViewDirective(unittest.TestCase): from zope.component import getSiteManager from repoze.bfg.interfaces import IRequest from repoze.bfg.interfaces import IView - from repoze.bfg.interfaces import IViewPermission - + from repoze.bfg.interfaces import IRendererFactory import repoze.bfg.tests context = DummyContext(repoze.bfg.tests) @@ -335,9 +334,17 @@ class TestViewDirective(unittest.TestCase): def __call__(self): return {'a':'1'} - import os + class Renderer: + def __call__(self, path): + self.path = path + return lambda *arg: 'Hello!' + + renderer = Renderer() + sm = getSiteManager() + sm.registerUtility(renderer, IRendererFactory, name='.txt') + fixture = 'fixtures/minimal.txt' - self._callFUT(context, 'repoze.view', IFoo, view=view, template=fixture) + self._callFUT(context, 'repoze.view', IFoo, view=view, renderer=fixture) actions = context.actions self.assertEqual(len(actions), 1) @@ -347,29 +354,33 @@ class TestViewDirective(unittest.TestCase): self.assertEqual(action['discriminator'], discrim) register = action['callable'] register() - sm = getSiteManager() wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='') self.assertEqual(wrapper.__module__, view.__module__) self.assertEqual(wrapper.__name__, view.__name__) self.assertEqual(wrapper.__doc__, view.__doc__) - result = wrapper(None, None) - self.assertEqual(result.body, 'Hello.\n') + request = DummyRequest() + result = wrapper(None, request) + self.assertEqual(result.body, 'Hello!') + self.assertEqual(renderer.path, 'repoze.bfg.tests:fixtures/minimal.txt') def test_with_template_no_view_callable(self): from zope.interface import Interface from zope.component import getSiteManager from repoze.bfg.interfaces import IRequest from repoze.bfg.interfaces import IView - from repoze.bfg.interfaces import IViewPermission + from repoze.bfg.interfaces import IRendererFactory import repoze.bfg.tests context = DummyContext(repoze.bfg.tests) class IFoo(Interface): pass - import os - fixture = 'fixtures/minimal.txt' - self._callFUT(context, 'repoze.view', IFoo, template=fixture) + sm = getSiteManager() + def renderer_factory(path): + return lambda *arg: 'Hello!' + sm.registerUtility(renderer_factory, IRendererFactory, name='.txt') + + self._callFUT(context, 'repoze.view', IFoo, renderer='foo.txt') actions = context.actions self.assertEqual(len(actions), 1) @@ -379,10 +390,11 @@ class TestViewDirective(unittest.TestCase): self.assertEqual(action['discriminator'], discrim) register = action['callable'] register() - sm = getSiteManager() wrapper = sm.adapters.lookup((IFoo, IRequest), IView, name='') - result = wrapper(None, None) - self.assertEqual(result.body, 'Hello.\n') + request = DummyRequest() + request.environ = {} + result = wrapper(None, request) + self.assertEqual(result.body, 'Hello!') def test_request_type_asinterface(self): from zope.component import getSiteManager diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py index ba96812e7..0f899df53 100644 --- a/repoze/bfg/view.py +++ b/repoze/bfg/view.py @@ -26,15 +26,16 @@ from zope.interface import implements from zope.deprecation import deprecated from repoze.bfg.interfaces import IResponseFactory +from repoze.bfg.interfaces import IRendererFactory from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IMultiView +from repoze.bfg.interfaces import ITemplateRenderer from repoze.bfg.path import caller_package from repoze.bfg.static import PackageURLParser -from repoze.bfg.templating import renderer_from_path -from repoze.bfg.templating import _auto_reload +from repoze.bfg.renderers import renderer_from_name deprecated('view_execution_permitted', "('from repoze.bfg.view import view_execution_permitted' was " @@ -236,8 +237,8 @@ class bfg_view(object): function itself if the view is a function, or the ``__call__`` callable attribute if the view is a class). - If ``template`` is not supplied, ``None`` is used (meaning that no - template is associated with this view). + If ``renderer`` is not supplied, ``None`` is used (meaning that no + renderer is associated with this view). If ``wrapper`` is not supplied, ``None`` is used (meaning that no view wrapper is associated with this view). @@ -335,7 +336,7 @@ class bfg_view(object): """ def __init__(self, name='', request_type=None, for_=None, permission=None, route_name=None, request_method=None, request_param=None, - containment=None, attr=None, template=None, wrapper=None): + containment=None, attr=None, renderer='', wrapper=None): self.name = name self.request_type = request_type self.for_ = for_ @@ -345,11 +346,11 @@ class bfg_view(object): self.request_param = request_param self.containment = containment self.attr = attr - self.template = template + self.renderer = renderer self.wrapper_viewname = wrapper def __call__(self, wrapped): - _bfg_view = map_view(wrapped, self.attr, self.template) + _bfg_view = map_view(wrapped, self.attr, self.renderer) _bfg_view.__is_bfg_view__ = True _bfg_view.__permission__ = self.permission _bfg_view.__for__ = self.for_ @@ -430,41 +431,43 @@ class MultiView(object): continue raise NotFound(self.name) -def templated_response(template_name, response, view, context, request, - auto_reload=False): +def rendered_response(renderer_name, response, view, context, request): if is_response(response): return response - renderer = renderer_from_path(template_name, auto_reload=auto_reload) - kw = {'view':view, 'template_name':template_name, 'context':context, - 'request':request} - try: - kw.update(response) - except TypeError: - return response - result = renderer(**kw) + renderer = renderer_from_name(renderer_name) + if ITemplateRenderer.providedBy(renderer): + kw = {'view':view, 'template_name':renderer_name, 'context':context, + 'request':request} + try: + kw.update(response) + except TypeError: + return response + result = renderer(kw) + else: + result = renderer(response) response_factory = queryUtility(IResponseFactory, default=Response) response = response_factory(result) - content_type = kw.get('content_type_', None) + attrs = request.environ.get('webob.adhoc_attrs', {}) + content_type = attrs.get('response_content_type', None) if content_type is not None: response.content_type = content_type - headerlist = kw.get('headerlist_', None) + headerlist = attrs.get('response_headerlist', None) if headerlist is not None: for k, v in headerlist: response.headers.add(k, v) - status = kw.get('status_', None) + status = attrs.get('response_status', None) if status is not None: response.status = status - charset = kw.get('charset_', None) + charset = attrs.get('response_charset', None) if charset is not None: response.charset = charset - cache_for = kw.get('cache_for_', None) + cache_for = attrs.get('response_cache_for', None) if cache_for is not None: response.cache_expires = cache_for return response -def map_view(view, attr=None, template=None): +def map_view(view, attr=None, renderer=None): wrapped_view = view - auto_reload = _auto_reload() if inspect.isclass(view): # If the object we've located is a class, turn it into a @@ -482,9 +485,9 @@ def map_view(view, attr=None, template=None): response = inst() else: response = getattr(inst, attr)() - if template: - response = templated_response(template, response, inst, - context, request, auto_reload) + if renderer: + response = rendered_response(renderer, response, inst, + context, request) return response wrapped_view = _bfg_class_requestonly_view else: @@ -495,9 +498,9 @@ def map_view(view, attr=None, template=None): response = inst() else: response = getattr(inst, attr)() - if template: - response = templated_response(template, response, inst, - context, request, auto_reload) + if renderer: + response = rendered_response(renderer, response, inst, + context, request) return response wrapped_view = _bfg_class_view @@ -510,28 +513,36 @@ def map_view(view, attr=None, template=None): else: response = getattr(view, attr)(request) - if template: - response = templated_response(template, response, view, - context, request, auto_reload) + if renderer: + response = rendered_response(renderer, response, view, + context, request) return response wrapped_view = _bfg_requestonly_view elif attr: def _bfg_attr_view(context, request): response = getattr(view, attr)(context, request) - if template: - response = templated_response(template, response, view, - context, request, auto_reload) + if renderer: + response = rendered_response(renderer, response, view, + context, request) return response wrapped_view = _bfg_attr_view - elif template: - def _templated_view(context, request): + elif renderer: + def _rendered_view(context, request): + response = view(context, request) + response = rendered_response(renderer, response, view, + context, request) + return response + wrapped_view = _rendered_view + + elif queryUtility(IRendererFactory): + def _default_rendered_view(context, request): response = view(context, request) - response = templated_response(template, response, view, - context, request, auto_reload) + response = rendered_response(renderer, response, view, + context, request) return response - wrapped_view = _templated_view + wrapped_view = _default_rendered_view decorate_view(wrapped_view, view) return wrapped_view diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py index ff2549447..94bb7371d 100644 --- a/repoze/bfg/zcml.py +++ b/repoze/bfg/zcml.py @@ -39,7 +39,7 @@ from repoze.bfg.interfaces import ILogger from repoze.bfg.interfaces import IPackageOverrides from repoze.bfg.interfaces import IRequest from repoze.bfg.interfaces import IRouteRequest -from repoze.bfg.interfaces import ITemplateRendererFactory +from repoze.bfg.interfaces import IRendererFactory from repoze.bfg.path import package_name @@ -83,18 +83,18 @@ def view( request_param=None, containment=None, attr=None, - template=None, + renderer=None, wrapper=None, cacheable=True, # not used, here for b/w compat < 0.8 ): if not view: - if template: + if renderer: def view(context, request): return {} else: raise ConfigurationError('"view" attribute was not specified and ' - 'no template specified') + 'no renderer specified') sm = getSiteManager() @@ -173,14 +173,15 @@ def view( else: score = sys.maxint - if template and (not ':' in template) and (not os.path.isabs(template)): - # if it's not a package:relative/name and it's not an - # /absolute/path it's a relative/path; this means its relative - # to the package in which the ZCML file is defined. - template = '%s:%s' % (package_name(_context.resolve('.')), template) + if renderer and '.' in renderer: + if (not ':' in renderer) and (not os.path.isabs(renderer) ): + # if it's not a package:relative/name and it's not an + # /absolute/path it's a relative/path; this means its relative + # to the package in which the ZCML file is defined. + renderer = '%s:%s' % (package_name(_context.resolve('.')), renderer) def register(): - derived_view = derive_view(view, permission, predicates, attr, template, + derived_view = derive_view(view, permission, predicates, attr, renderer, wrapper) r_for_ = for_ r_request_type = request_type @@ -251,8 +252,8 @@ def forbidden(_context, view): view_utility(_context, view, IForbiddenView) def derive_view(original_view, permission=None, predicates=(), attr=None, - template=None, wrapper_viewname=None): - mapped_view = map_view(original_view, attr, template) + renderer=None, wrapper_viewname=None): + mapped_view = map_view(original_view, attr, renderer) owrapped_view = owrap_view(mapped_view, wrapper_viewname) secured_view = secure_view(owrapped_view, permission) debug_view = authdebug_view(secured_view, permission) @@ -560,21 +561,21 @@ def connect_route(path, name, factory): mapper = getUtility(IRoutesMapper) mapper.connect(path, name, factory) -class ITemplateRendererDirective(Interface): - renderer = GlobalObject( - title=u'ITemplateRendererFactory implementation', +class IRendererDirective(Interface): + factory = GlobalObject( + title=u'IRendererFactory implementation', required=True) - extension = TextLine( - title=u'Filename extension (e.g. ".pt")', + name = TextLine( + title=u'Token (e.g. ``json``) or filename extension (e.g. ".pt")', required=False) -def template_renderer(_context, renderer, extension=''): +def renderer(_context, factory, name=''): # renderer factories must be registered eagerly so they can be # found by the view machinery sm = getSiteManager() - sm.registerUtility(renderer, ITemplateRendererFactory, name=extension) - _context.action(discriminator=(ITemplateRendererFactory, extension)) + sm.registerUtility(factory, IRendererFactory, name=name) + _context.action(discriminator=(IRendererFactory, name)) class IStaticDirective(Interface): name = TextLine( @@ -642,8 +643,8 @@ class IViewDirective(Interface): description=u'', required=False) - template = TextLine( - title=u'The template asssociated with the view', + renderer = TextLine( + title=u'The renderer asssociated with the view', description=u'', required=False) -- cgit v1.2.3