summaryrefslogtreecommitdiff
path: root/repoze
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-09-16 04:56:49 +0000
committerChris McDonough <chrism@agendaless.com>2009-09-16 04:56:49 +0000
commita9fed7675d8da572dee840676714b2653e3f7f79 (patch)
tree93327afae95fb9cf6b1d0cb72da265af42a705bd /repoze
parenta37220b84dee4cc8b1b12f34643ce97dad89ffe1 (diff)
downloadpyramid-a9fed7675d8da572dee840676714b2653e3f7f79.tar.gz
pyramid-a9fed7675d8da572dee840676714b2653e3f7f79.tar.bz2
pyramid-a9fed7675d8da572dee840676714b2653e3f7f79.zip
Checkpoint. Not 100% test coverage.
Diffstat (limited to 'repoze')
-rw-r--r--repoze/bfg/chameleon_text.py61
-rw-r--r--repoze/bfg/chameleon_zpt.py46
-rw-r--r--repoze/bfg/includes/configure.zcml16
-rw-r--r--repoze/bfg/includes/meta.zcml6
-rw-r--r--repoze/bfg/interfaces.py23
-rw-r--r--repoze/bfg/renderers.py (renamed from repoze/bfg/templating.py)73
-rw-r--r--repoze/bfg/testing.py2
-rw-r--r--repoze/bfg/tests/test_chameleon_text.py4
-rw-r--r--repoze/bfg/tests/test_chameleon_zpt.py2
-rw-r--r--repoze/bfg/tests/test_renderers.py (renamed from repoze/bfg/tests/test_templating.py)38
-rw-r--r--repoze/bfg/tests/test_testing.py8
-rw-r--r--repoze/bfg/tests/test_view.py142
-rw-r--r--repoze/bfg/tests/test_zcml.py40
-rw-r--r--repoze/bfg/view.py93
-rw-r--r--repoze/bfg/zcml.py45
15 files changed, 357 insertions, 242 deletions
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"
/>
- <template_renderer
- renderer="repoze.bfg.chameleon_zpt.ZPTTemplateRenderer"
- extension=".pt"
+ <renderer
+ factory="repoze.bfg.chameleon_zpt.renderer_factory"
+ name=".pt"
+ />
+
+ <renderer
+ factory="repoze.bfg.chameleon_text.renderer_factory"
+ name=".txt"
+ />
+
+ <renderer
+ factory="repoze.bfg.renderers.json_renderer_factory"
+ name="json"
/>
</configure>
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 @@
/>
<meta:directive
- name="template_renderer"
- schema="repoze.bfg.zcml.ITemplateRendererDirective"
- handler="repoze.bfg.zcml.template_renderer"
+ name="renderer"
+ schema="repoze.bfg.zcml.IRendererDirective"
+ handler="repoze.bfg.zcml.renderer"
/>
</meta:directives>
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/templating.py b/repoze/bfg/renderers.py
index 2ec049ca5..495a35541 100644
--- a/repoze/bfg/templating.py
+++ b/repoze/bfg/renderers.py
@@ -4,43 +4,27 @@ 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)
+from repoze.bfg.interfaces import IRendererFactory
+from repoze.bfg.interfaces import ITemplateRenderer
+
+try:
+ import json
+except ImportError:
+ import simplejson as json
-class TextTemplateRenderer(object):
- classProvides(ITemplateRendererFactory)
- implements(ITemplateRenderer)
+# concrete renderer factory implementations
- def __init__(self, path, auto_reload=False):
- self.template = TextTemplateFile(path, format='text',
- auto_reload=auto_reload)
+def json_renderer_factory(name):
+ def _render(value):
+ return json.dumps(value)
+ return _render
- def implementation(self):
- return self.template
-
- def __call__(self, **kw):
- return self.template(**kw)
+# utility functions
-def renderer_from_cache(path, factory, level=3, **kw):
+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)
@@ -48,7 +32,7 @@ def renderer_from_cache(path, factory, level=3, **kw):
raise ValueError('Missing template file: %s' % path)
renderer = queryUtility(ITemplateRenderer, name=path)
if renderer is None:
- renderer = factory(path, **kw)
+ renderer = impl(path)
sm = getSiteManager()
sm.registerUtility(renderer, ITemplateRenderer, name=path)
@@ -72,9 +56,8 @@ def renderer_from_cache(path, factory, level=3, **kw):
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')):
+ renderer = impl(abspath)
+ if not _reload_resources():
# cache the template
sm = getSiteManager()
sm.registerUtility(renderer, ITemplateRenderer,
@@ -82,14 +65,18 @@ def renderer_from_cache(path, factory, level=3, **kw):
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 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 _auto_reload():
- settings = queryUtility(ISettings)
- auto_reload = settings and settings['reload_templates']
- return auto_reload
+def _reload_resources():
+ settings = get_settings()
+ if settings:
+ return settings['reload_resources']
+ return False
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,
'<div xmlns="http://www.w3.org/1999/xhtml">\n</div>')
diff --git a/repoze/bfg/tests/test_templating.py b/repoze/bfg/tests/test_renderers.py
index c3894cce4..aa159cc18 100644
--- a/repoze/bfg/tests/test_templating.py
+++ b/repoze/bfg/tests/test_renderers.py
@@ -3,16 +3,16 @@ import unittest
from repoze.bfg.testing import cleanUp
from repoze.bfg import testing
-class TestRendererFromCache(unittest.TestCase):
+class TestTemplateRendererFactory(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 _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
@@ -87,10 +87,10 @@ class TestRendererFromCache(unittest.TestCase):
import os
from repoze.bfg.tests import test_templating
module_name = test_templating.__name__
- relpath = 'test_templating.py'
+ relpath = 'test_renderers.py'
renderer = {}
factory = DummyFactory(renderer)
- result = self._callFUT('test_templating.py', factory)
+ result = self._callFUT('test_renderers.py', factory)
self.failUnless(result is renderer)
path = os.path.abspath(__file__)
if path.endswith('pyc'): # pragma: no cover
@@ -102,7 +102,7 @@ class TestRendererFromCache(unittest.TestCase):
import os
from repoze.bfg import tests
module_name = tests.__name__
- relpath = 'test_templating.py'
+ relpath = 'test_renderers.py'
renderer = {}
factory = DummyFactory(renderer)
spec = '%s:%s' % (module_name, relpath)
@@ -122,9 +122,9 @@ class TestRendererFromCache(unittest.TestCase):
testing.registerUtility(settings, ISettings)
renderer = {}
factory = DummyFactory(renderer)
- result = self._callFUT('test_templating.py', factory)
+ result = self._callFUT('test_renderers.py', factory)
self.failUnless(result is renderer)
- spec = '%s:%s' % ('repoze.bfg.tests', 'test_templating.py')
+ spec = '%s:%s' % ('repoze.bfg.tests', 'test_renderers.py')
self.assertEqual(queryUtility(ITemplateRenderer, name=spec),
None)
@@ -136,9 +136,9 @@ class TestRendererFromCache(unittest.TestCase):
testing.registerUtility(settings, ISettings)
renderer = {}
factory = DummyFactory(renderer)
- result = self._callFUT('test_templating.py', factory)
+ result = self._callFUT('test_renderers.py', factory)
self.failUnless(result is renderer)
- spec = '%s:%s' % ('repoze.bfg.tests', 'test_templating.py')
+ spec = '%s:%s' % ('repoze.bfg.tests', 'test_renderers.py')
self.assertNotEqual(queryUtility(ITemplateRenderer, name=spec),
None)
@@ -149,19 +149,11 @@ class TestRendererFromPath(unittest.TestCase):
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 _callFUT(self, path, level=4):
+ from repoze.bfg.renderers import renderer_from_name
+ return renderer_from_name(path, level)
- def test_with_nondefault(self):
+ def test_it(self):
from repoze.bfg.interfaces import ITemplateRendererFactory
import os
here = os.path.dirname(os.path.abspath(__file__))
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)