summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2008-07-14 18:27:19 +0000
committerChris McDonough <chrism@agendaless.com>2008-07-14 18:27:19 +0000
commited334fdfefcdfdc570cfcd42aff171b177b76240 (patch)
treee716196772096510a99f8445945f97c4af78680c
parentbaf2406e1999160ad5d96e3adbeb525502a6d98b (diff)
downloadpyramid-ed334fdfefcdfdc570cfcd42aff171b177b76240.tar.gz
pyramid-ed334fdfefcdfdc570cfcd42aff171b177b76240.tar.bz2
pyramid-ed334fdfefcdfdc570cfcd42aff171b177b76240.zip
Render templates explicitly in views.
-rw-r--r--README.txt29
-rw-r--r--repoze/bfg/__init__.py2
-rw-r--r--repoze/bfg/sampleapp/configure.zcml18
-rw-r--r--repoze/bfg/sampleapp/templates/blog.pt6
-rw-r--r--repoze/bfg/sampleapp/templates/blog_entry.pt6
-rw-r--r--repoze/bfg/sampleapp/templates/blog_entry_add.pt15
-rw-r--r--repoze/bfg/sampleapp/views.py97
-rw-r--r--repoze/bfg/template.py36
-rw-r--r--repoze/bfg/tests/fixtureapp/configure.zcml1
-rw-r--r--repoze/bfg/tests/fixtureapp/views.py4
-rw-r--r--repoze/bfg/tests/test_template.py6
-rw-r--r--repoze/bfg/tests/test_view.py30
-rw-r--r--repoze/bfg/tests/test_zcml.py129
-rw-r--r--repoze/bfg/view.py22
-rw-r--r--repoze/bfg/zcml.py65
15 files changed, 210 insertions, 256 deletions
diff --git a/README.txt b/README.txt
index 104f321cb..e3f1f6ea5 100644
--- a/README.txt
+++ b/README.txt
@@ -268,23 +268,14 @@ A views.py module might look like so::
from webob import Response
from repoze.bfg.view import TemplateView
- class MyHelloView(object):
- def __init__(self, context, request):
- self.context = context
- self.request = request
+ def my_hello_view(context, request):
+ response = Response('Hello from %s @ %s' % (
+ context.__name__,
+ request.environ['PATH_INFO']))
+ return response
- def __call__(self):
- response = Response('Hello from %s @ %s' % (
- self.context.__name__,
- self.request.environ['PATH_INFO']))
- return response
-
- class MyTemplateView(TemplateView):
-
- template = 'templates/my.pt'
-
- def getInfo(self):
- return {'name':self.context.__name__}
+ def my_template_view(context, request):
+ return render_template('templates/my.pt', name=context.__name__)
models.py
~~~~~~~~~
@@ -335,7 +326,7 @@ A view registry might look like so::
permission="repoze.view"
/>
- <!-- the templated view for a MyModel -->
+ <!-- the templated.html view for a MyModel -->
<bfg:view
for=".models.IMyModel"
factory=".views.MyTemplateView"
@@ -353,8 +344,8 @@ A template that is used by a view might look like so::
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal">
<head></head>
- <body tal:define="info view.getInfo()">
- <h1>My template viewing ${info.name}</h1>
+ <body>
+ <h1>My template viewing ${name}</h1>
</body>
</html>
diff --git a/repoze/bfg/__init__.py b/repoze/bfg/__init__.py
index 76bdd005d..7add3dca8 100644
--- a/repoze/bfg/__init__.py
+++ b/repoze/bfg/__init__.py
@@ -1,2 +1,2 @@
from repoze.bfg.router import make_app # for import elsewhere
-from repoze.bfg.view import View
+from repoze.bfg.template import render_template
diff --git a/repoze/bfg/sampleapp/configure.zcml b/repoze/bfg/sampleapp/configure.zcml
index 5e7a83ffd..e026a12f2 100644
--- a/repoze/bfg/sampleapp/configure.zcml
+++ b/repoze/bfg/sampleapp/configure.zcml
@@ -7,39 +7,29 @@
<!-- the default view for a Blog -->
<bfg:view
for=".models.IBlog"
- factory=".views.BlogDefaultView"
- template="templates/blog.pt"
+ factory=".views.blog_default_view"
permission="repoze.view"
/>
<!-- the default view for a BlogEntry -->
<bfg:view
for=".models.IBlogEntry"
- factory=".views.BlogEntryDefaultView"
- template="templates/blog_entry.pt"
+ factory=".views.blog_entry_default_view"
permission="repoze.view"
/>
<!-- the add template for a BlogEntry -->
<bfg:view
for=".models.IBlog"
- template="templates/blog_entry_add.pt"
+ factory=".views.blog_entry_add_view"
name="add_entry.html"
permission="repoze.view"
/>
- <!-- the add handler for a BlogEntry -->
- <bfg:view
- for=".models.IBlog"
- factory=".views.BlogEntryAddView"
- permission="repoze.view"
- name="add_entry_handler"
- />
-
<!-- the contents view for any mapping (shows dict members) -->
<bfg:view
for=".models.IMapping"
- template="templates/contents.pt"
+ factory=".views.contents_view"
name="contents.html"
permission="repoze.view"
/>
diff --git a/repoze/bfg/sampleapp/templates/blog.pt b/repoze/bfg/sampleapp/templates/blog.pt
index 8ccbe56a2..8eb3945db 100644
--- a/repoze/bfg/sampleapp/templates/blog.pt
+++ b/repoze/bfg/sampleapp/templates/blog.pt
@@ -1,15 +1,15 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal">
<head></head>
-<body tal:define="info view.getInfo()">
- <h1 tal:content="info.name">Blog Name</h1>
+<body>
+ <h1 tal:content="name">Blog Name</h1>
<table border="0">
<thead>
<th>Title</th>
<th>Author</th>
<th>Created</th>
</thead>
- <tr tal:repeat="entry info.entries">
+ <tr tal:repeat="entry entries">
<td><a href="${entry.name}/">${entry.title}</a></td>
<td>${entry.author}</td>
<td>${entry.created}</td>
diff --git a/repoze/bfg/sampleapp/templates/blog_entry.pt b/repoze/bfg/sampleapp/templates/blog_entry.pt
index 20e1b4409..830876525 100644
--- a/repoze/bfg/sampleapp/templates/blog_entry.pt
+++ b/repoze/bfg/sampleapp/templates/blog_entry.pt
@@ -2,10 +2,10 @@
xmlns:tal="http://xml.zope.org/namespaces/tal">
<head></head>
<body>
- <div tal:define="info view.getInfo()">
+ <div>
<p><a href="..">Up</a></p>
- <h1>${info.title}</h1>
- <p>by ${info.author}</p>
+ <h1>${title}</h1>
+ <p>by ${author}</p>
<div tal:content="structure info.body"></div>
</div>
</body>
diff --git a/repoze/bfg/sampleapp/templates/blog_entry_add.pt b/repoze/bfg/sampleapp/templates/blog_entry_add.pt
index b41ae4b02..101163b44 100644
--- a/repoze/bfg/sampleapp/templates/blog_entry_add.pt
+++ b/repoze/bfg/sampleapp/templates/blog_entry_add.pt
@@ -1,24 +1,27 @@
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:tal="http://xml.zope.org/namespaces/tal">
-<head></head>
+<head>
+</head>
<body>
- <form action="add_entry_handler" method="POST">
+ <form action="${request.path_url}" method="POST">
+ <h2 tal:condition="message" tal:content="message"></h2>
<h1>Add a blog entry</h1>
<table border="0">
<tr>
<th>Title</th>
- <td><input type="text" name="title"/></td>
+ <td><input type="text" name="title"/>${title}</td>
</tr>
<tr>
<th>Author</th>
- <td><input type="text" name="author"/></td>
+ <td><input type="text" name="author"/>${author}</td>
</tr>
<tr>
<th>Body</th>
- <td><textarea name="body" rows="10" value=""> </textarea></td>
+ <td><textarea name="body" rows="10" cols="80"> ${body}</textarea
+ ></td>
</tr>
<tr>
- <td><input type="submit" name="add" value="Add"/></td>
+ <td><input type="submit" name="form.submitted" value="Add"/></td>
</tr>
</table>
</form>
diff --git a/repoze/bfg/sampleapp/views.py b/repoze/bfg/sampleapp/views.py
index 196fce703..8e2ddd467 100644
--- a/repoze/bfg/sampleapp/views.py
+++ b/repoze/bfg/sampleapp/views.py
@@ -1,49 +1,74 @@
+import formencode
import time
from webob.exc import HTTPFound
-from repoze.bfg.view import TemplateView
-from repoze.bfg.view import View
-
+from repoze.bfg.template import render_template
from repoze.bfg.sampleapp.models import BlogEntry
def datestring(dt):
return dt.strftime('%Y-%m-%d %H:%M:%S')
-class BlogDefaultView(TemplateView):
-
- def getInfo(self):
- entrydata = []
- for name, entry in self.context.items():
- entrydata.append(
- {
- 'name':name,
- 'title':entry.title,
- 'author':entry.author,
- 'created':datestring(entry.created),
- }
- )
- return {'name':self.context.__name__, 'entries':entrydata}
-
-class BlogEntryDefaultView(TemplateView):
-
- def getInfo(self):
- return {
- 'name':self.context.__name__,
- 'title':self.context.title,
- 'body':self.context.body,
- 'author':self.context.author,
- 'created':datestring(self.context.created),
+def blog_default_view(context, request):
+ entrydata = []
+ for name, entry in self.context.items():
+ entrydata.append(
+ {
+ 'name':name,
+ 'title':entry.title,
+ 'author':entry.author,
+ 'created':datestring(entry.created),
+ 'message':self.request.params.get('message'),
}
+ )
+
+ info = {'name':self.context.__name__, entries:entrydata}
+ return render_template('templates/blog.pt', info)
+
+def blog_entry_default_view(context, request):
+ info = {
+ 'name':self.context.__name__,
+ 'title':self.context.title,
+ 'body':self.context.body,
+ 'author':self.context.author,
+ 'created':datestring(self.context.created),
+ }
+ return render_template('templates/blog_entry.pt', **info)
+
+class BlogAddSchema(formencode.Schema):
+ allow_extra_fields = True
+ author = formencode.validators.NotEmpty()
+ body = formencode.validators.NotEmpty()
+ title = formencode.validators.NotEmpty()
+
+def blog_entry_add_view(context, request):
+ params = self.request.params
+
+ message = None
-class BlogEntryAddView(View):
+ author = params.get('author', '')
+ body = params.get('body', '')
+ title = params.get('title', '')
+ info = dict(request=self.request,
+ author=author, body=body, title=title, message=None)
- def __call__(self):
- author = self.request.params['author']
- body = self.request.params['body']
- title = self.request.params['title']
- name = str(time.time())
- new_entry = BlogEntry(name, title, body, author)
- self.context[name] = new_entry
- return HTTPFound(location='/')
+ if params.has_key('form.submitted'):
+ schema = BlogAddSchema()
+ try:
+ form = schema.to_python(params)
+ except formencode.validators.Invalid, why:
+ message = str(why)
+ info['message'] = message
+ else:
+ author = form['author']
+ body = form['body']
+ title = form['title']
+ name = str(time.time())
+ new_entry = BlogEntry(name, title, body, author)
+ self.context[name] = new_entry
+ return HTTPFound(location='/')
+ else:
+ return render_template('templates/blog_entry_add.pt', **info)
+def contents_view(context, request):
+ return render_template('templates/contents.pt', context=context)
diff --git a/repoze/bfg/template.py b/repoze/bfg/template.py
index c3e34c99a..4cd78f4f4 100644
--- a/repoze/bfg/template.py
+++ b/repoze/bfg/template.py
@@ -29,28 +29,32 @@ class Z3CPTTemplateFactory(object):
def package_path(package):
return os.path.abspath(os.path.dirname(package.__file__))
-def render_template(view, template_path, **kw):
+def registerTemplate(template, path):
+ try:
+ sm = getSiteManager()
+ except ComponentLookupError:
+ pass
+ else:
+ sm.registerUtility(template, IView, name=path)
+
+def render_template_explicit(path, **kw):
# XXX use pkg_resources
- if not os.path.isabs(template_path):
+ if not os.path.isabs(path):
package_globals = sys._getframe(1).f_globals
package_name = package_globals['__name__']
package = sys.modules[package_name]
prefix = package_path(package)
- template_path = os.path.join(prefix, template_path)
+ path = os.path.join(prefix, path)
- template = queryUtility(IView, template_path)
+ template = queryUtility(IView, path)
if template is None:
- if not os.path.exists(template_path):
- raise ValueError('Missing template file: %s' % template_path)
- template = Z3CPTTemplateFactory(template_path)
- try:
- sm = getSiteManager()
- except ComponentLookupError:
- pass
- else:
- sm.registerUtility(template, IView, name=template_path)
-
- return template(view=view, context=view.context, request=view.request,
- options=kw)
+ if not os.path.exists(path):
+ raise ValueError('Missing template file: %s' % path)
+ template = Z3CPTTemplateFactory(path)
+ registerTemplate(template, path)
+
+ return template(**kw)
+
+render_template = render_template_explicit
diff --git a/repoze/bfg/tests/fixtureapp/configure.zcml b/repoze/bfg/tests/fixtureapp/configure.zcml
index 99d0708aa..f08cd58ad 100644
--- a/repoze/bfg/tests/fixtureapp/configure.zcml
+++ b/repoze/bfg/tests/fixtureapp/configure.zcml
@@ -12,7 +12,6 @@
<bfg:view
for=".models.IFixture"
- factory=".views.FixtureTemplateView"
template="templates/fixture.pt"
permission="repoze.view"
name="fixture.html"
diff --git a/repoze/bfg/tests/fixtureapp/views.py b/repoze/bfg/tests/fixtureapp/views.py
index 36fe07cc6..b9b9fc7d9 100644
--- a/repoze/bfg/tests/fixtureapp/views.py
+++ b/repoze/bfg/tests/fixtureapp/views.py
@@ -1,5 +1,3 @@
-from repoze.bfg.view import TemplateView
-
class FixtureView(object):
def __init__(self, context, request):
self.context = context
@@ -8,5 +6,3 @@ class FixtureView(object):
def __call__(self):
pass
-class FixtureTemplateView(TemplateView):
- pass
diff --git a/repoze/bfg/tests/test_template.py b/repoze/bfg/tests/test_template.py
index 59dce3efa..96129504d 100644
--- a/repoze/bfg/tests/test_template.py
+++ b/repoze/bfg/tests/test_template.py
@@ -78,9 +78,8 @@ class RenderTemplateTests(unittest.TestCase, Base):
from repoze.bfg.interfaces import IView
minimal = self._getTemplatePath('minimal.pt')
self.assertEqual(queryUtility(IView, minimal), None)
- view = DummyView()
render = self._getFUT()
- result = render(view, minimal)
+ result = render(minimal)
from webob import Response
self.failUnless(isinstance(result, Response))
self.assertEqual(result.app_iter, ['<div>\n</div>'])
@@ -100,9 +99,8 @@ class RenderTemplateTests(unittest.TestCase, Base):
utility = Z3CPTTemplateFactory(minimal)
gsm = getGlobalSiteManager()
gsm.registerUtility(utility, IView, name=minimal)
- view = DummyView()
render = self._getFUT()
- result = render(view, minimal)
+ result = render(minimal)
from webob import Response
self.failUnless(isinstance(result, Response))
self.assertEqual(result.app_iter, ['<div>\n</div>'])
diff --git a/repoze/bfg/tests/test_view.py b/repoze/bfg/tests/test_view.py
index 7d87b9c83..b6982f431 100644
--- a/repoze/bfg/tests/test_view.py
+++ b/repoze/bfg/tests/test_view.py
@@ -32,33 +32,3 @@ class ViewTests(unittest.TestCase):
view = self._makeOne(None, None)
self.assertRaises(NotImplementedError, view)
-class TemplateViewTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
- def _getTargetClass(self):
- from repoze.bfg.view import TemplateView
- return TemplateView
-
- def _makeOne(self, *arg, **kw):
- klass = self._getTargetClass()
- return klass(*arg, **kw)
-
- def test_call(self):
- self._zcmlConfigure()
- view = self._makeOne(None, None)
- view.template = self._getTemplatePath('minimal.pt')
- result = view(foo='foo')
- from webob import Response
- self.failUnless(isinstance(result, Response))
- self.assertEqual(result.app_iter, ['<div>\n</div>'])
- self.assertEqual(result.status, '200 OK')
- self.assertEqual(len(result.headerlist), 2)
-
- def test_call_no_template(self):
- self._zcmlConfigure()
- view = self._makeOne(None, None)
- self.assertRaises(ValueError, view)
diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py
index f87c49424..db826b687 100644
--- a/repoze/bfg/tests/test_zcml.py
+++ b/repoze/bfg/tests/test_zcml.py
@@ -103,101 +103,72 @@ class TestViewDirective(unittest.TestCase, PlacelessSetup):
def test_template_and_factory(self):
f = self._getFUT()
context = DummyContext()
- class IFoo:
- pass
- class DummyView:
- pass
- f(context, 'repoze.view', IFoo, factory=DummyView,
- template='minimal.pt')
- actions = context.actions
- from repoze.bfg.interfaces import IView
- from repoze.bfg.interfaces import IRequest
- from repoze.bfg.interfaces import IViewFactory
- from zope.component.zcml import handler
- from zope.component.interface import provideInterface
-
- self.assertEqual(len(actions), 3)
-
- regutil_discriminator = ('utility', IView, context.path('minimal.pt'))
- regutil = actions[0]
- self.assertEqual(regutil['discriminator'], regutil_discriminator)
- self.assertEqual(regutil['callable'], handler)
- self.assertEqual(regutil['args'][0], 'registerUtility')
- self.assertEqual(regutil['args'][1].template.filename,
- context.path('minimal.pt'))
- self.assertEqual(regutil['args'][2], IView)
- self.assertEqual(regutil['args'][3], context.path('minimal.pt'))
-
- provide = actions[1]
- self.assertEqual(provide['discriminator'], None)
- self.assertEqual(provide['callable'], provideInterface)
- self.assertEqual(provide['args'][0], '')
- self.assertEqual(provide['args'][1], IFoo)
-
- regadapt = actions[2]
- regadapt_discriminator = ('view', IFoo, '', IRequest, IViewFactory)
- self.assertEqual(regadapt['discriminator'], regadapt_discriminator)
- self.assertEqual(regadapt['callable'], handler)
- self.assertEqual(regadapt['args'][0], 'registerAdapter')
- self.assertEqual(regadapt['args'][1].template,
- context.path('minimal.pt'))
- self.assertEqual(regadapt['args'][2], (IFoo, IRequest))
- self.assertEqual(regadapt['args'][3], IViewFactory)
- self.assertEqual(regadapt['args'][4], '')
- self.assertEqual(regadapt['args'][5], None)
+ from zope.configuration.exceptions import ConfigurationError
+ self.assertRaises(ConfigurationError, f, context, 'repoze.view',
+ None, factory=object, template='minimal.pt')
-class TestTemplateViewFactory(unittest.TestCase):
+class TestTemplateOnlyViewFactory(unittest.TestCase):
def _getTargetClass(self):
- from repoze.bfg.zcml import TemplateViewFactory
- return TemplateViewFactory
+ from repoze.bfg.zcml import TemplateOnlyViewFactory
+ return TemplateOnlyViewFactory
- def _makeOne(self, template, base=None):
- return self._getTargetClass()(template, base)
+ def _makeOne(self, template):
+ return self._getTargetClass()(template)
def test_instance_conforms_to_IViewFactory(self):
from zope.interface.verify import verifyObject
from repoze.bfg.interfaces import IViewFactory
verifyObject(IViewFactory, self._makeOne('a'))
- def test_call_templateonly(self):
+ def test_call(self):
context = DummyContext()
template = context.path('minimal.pt')
factory = self._makeOne(template)
view = factory(None, None)
- from repoze.bfg.view import TemplateView
- self.failUnless(isinstance(view, TemplateView))
+ from repoze.bfg.zcml import TemplateOnlyView
+ self.failUnless(isinstance(view, TemplateOnlyView))
self.assertEqual(view.template, template)
-
- def test_call_nonclassbase(self):
- context = DummyContext()
- def factory():
- pass
- template = context.path('minimal.pt')
- self.assertRaises(ValueError, self._makeOne, template, factory)
- def test_call_classbase_not_templateview_subclass(self):
- context = DummyContext()
- template = context.path('minimal.pt')
- factory = self._makeOne(template, Dummy)
- view = factory(None, None)
- from repoze.bfg.view import TemplateView
- self.assertEqual(view.__bases__[0], Dummy)
- self.assertEqual(view.__bases__[1], TemplateView)
- self.assertEqual(view.__name__, 'DynamicTemplateView_For_Dummy')
- self.assertEqual(view.template, template)
+class TemplateOnlyViewTests(unittest.TestCase, PlacelessSetup):
+ def setUp(self):
+ PlacelessSetup.setUp(self)
- def test_call_classbase_templateview_subclass(self):
- context = DummyContext()
- template = context.path('minimal.pt')
- from repoze.bfg.view import TemplateView
- class TemplateViewSubclass(TemplateView):
- pass
- factory = self._makeOne(template, TemplateViewSubclass)
- view = factory(None, None)
- self.assertEqual(view.__bases__[0], TemplateViewSubclass)
- self.assertEqual(view.__name__,
- 'DynamicTemplateView_For_TemplateViewSubclass')
- self.assertEqual(view.template, template)
+ def tearDown(self):
+ PlacelessSetup.tearDown(self)
+
+ def _getTargetClass(self):
+ from repoze.bfg.zcml import TemplateOnlyView
+ return TemplateOnlyView
+
+ def _zcmlConfigure(self):
+ import repoze.bfg
+ import zope.configuration.xmlconfig
+ zope.configuration.xmlconfig.file('configure.zcml', package=repoze.bfg)
+
+ def _getTemplatePath(self, name):
+ import os
+ here = os.path.abspath(os.path.dirname(__file__))
+ return os.path.join(here, 'fixtures', name)
+
+ def _makeOne(self, *arg, **kw):
+ klass = self._getTargetClass()
+ return klass(*arg, **kw)
+
+ def test_call(self):
+ self._zcmlConfigure()
+ view = self._makeOne(None, None)
+ view.template = self._getTemplatePath('minimal.pt')
+ result = view(foo='foo')
+ from webob import Response
+ self.failUnless(isinstance(result, Response))
+ self.assertEqual(result.app_iter, ['<div>\n</div>'])
+ self.assertEqual(result.status, '200 OK')
+ self.assertEqual(len(result.headerlist), 2)
+
+ def test_call_no_template(self):
+ self._zcmlConfigure()
+ view = self._makeOne(None, None)
+ self.assertRaises(ValueError, view)
class TestSampleApp(unittest.TestCase, PlacelessSetup):
def setUp(self):
diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py
index 07c3d183d..e2ea156a0 100644
--- a/repoze/bfg/view.py
+++ b/repoze/bfg/view.py
@@ -1,7 +1,13 @@
-from repoze.bfg.template import render_template
+from zope.interface import implements
+from zope.interface import classProvides
+
+from repoze.bfg.interfaces import IView
+from repoze.bfg.interfaces import IViewFactory
class View(object):
""" Convenience base class for user-defined views """
+ implements(IView)
+ classProvides(IViewFactory)
def __init__(self, context, request):
self.context = context
self.request = request
@@ -9,19 +15,5 @@ class View(object):
def __call__(self, **kw):
raise NotImplementedError
-class TemplateView(View):
- template = None
- def __call__(self, **kw):
- if self.template is None:
- raise ValueError('a "template" attribute must be attached to '
- 'a TemplateView')
- return render_template(self, self.template, **kw)
-
- def __repr__(self):
- klass = self.__class__
- return '<%s.%s object at %s for %s>' % (klass.__module__,
- klass.__mame__,
- id(self),
- self.template)
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py
index dc05cca18..1cfdcf953 100644
--- a/repoze/bfg/zcml.py
+++ b/repoze/bfg/zcml.py
@@ -1,6 +1,4 @@
-import inspect
import os
-import new
from zope.component.zcml import handler
from zope.component.interface import provideInterface
@@ -8,10 +6,11 @@ from zope.configuration.exceptions import ConfigurationError
from zope.configuration.fields import GlobalObject
from zope.configuration.fields import Path
-from zope.schema import TextLine
from zope.interface import Interface
from zope.interface import implements
+from zope.interface import classProvides
+from zope.schema import TextLine
from zope.security.zcml import Permission
from repoze.bfg.interfaces import IRequest
@@ -19,31 +18,42 @@ from repoze.bfg.interfaces import IViewFactory
from repoze.bfg.interfaces import IView
from repoze.bfg.template import Z3CPTTemplateFactory
-from repoze.bfg.view import TemplateView
-
-class TemplateViewFactory(object):
- """ Pickleable template view factory """
+from repoze.bfg.template import render_template_explicit
+
+class TemplateOnlyView(object):
+ implements(IView)
+ classProvides(IViewFactory)
+ template = None
+
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self, **kw):
+ if self.template is None:
+ raise ValueError('a "template" attribute must be attached to '
+ 'a TemplateOnlyView')
+ kw = dict(view=self, context=self.context, request=self.request,
+ options=kw)
+ return render_template_explicit(self.template, **kw)
+
+ def __repr__(self):
+ klass = self.__class__
+ return '<%s.%s object at %s for %s>' % (klass.__module__,
+ klass.__mame__,
+ id(self),
+ self.template)
+
+class TemplateOnlyViewFactory(object):
+ """ Pickleable template-only view factory """
implements(IViewFactory)
- def __init__(self, template, base=None):
- if base is not None:
- if not inspect.isclass(base):
- raise ValueError('Factory must be a class to be used '
- 'with a template, but %s was supplied' % base)
+ def __init__(self, template):
self.template = template
- self.base = base
def __call__(self, context, request):
- if self.base and self.base is not TemplateView:
- if issubclass(self.base, TemplateView):
- bases = (self.base,)
- else:
- bases = (self.base, TemplateView)
- name = 'DynamicTemplateView_For_%s' % self.base.__name__
- factory = new.classobj(name, bases, {})
- else:
- factory = TemplateView(context, request)
+ factory = TemplateOnlyView(context, request)
factory.template = self.template
return factory
@@ -57,9 +67,9 @@ def view(_context,
# XXX we do nothing yet with permission
- if not (template or factory):
+ if (template and factory):
raise ConfigurationError(
- 'One of template or factory (or both) must be specified')
+ 'One of template or factory must be specified, not both')
if template:
template_abs = os.path.abspath(str(_context.path(template)))
@@ -71,7 +81,12 @@ def view(_context,
callable = handler,
args = ('registerUtility', utility, IView, template_abs),
)
- factory = TemplateViewFactory(template_abs, factory)
+ factory = TemplateOnlyViewFactory(template_abs)
+
+ if not factory:
+ raise ConfigurationError(
+ 'Neither template nor factory was specified, though one must be '
+ 'specified.')
if for_ is not None:
_context.action(