Commit 58f5e30e authored by Tres Seaver's avatar Tres Seaver

Remove all use of ``zope.app.pagetemplate`` by cloning / simplifying code.

o Added tests for previously-untested clients.
parent 97dce912
......@@ -18,10 +18,10 @@ Zope2 depends on the following zope.app packages directly:
- [_] zope.app.form
o Products.Five.form.*
- [_] zope.app.pagetemplate
o Products.PageTemplates.Expressions
o Products.Five.browser.pagetemplatefile
o Products.Five.browser.metaconfigure
- [X] zope.app.pagetemplate
* Products.PageTemplates.Expressions
* Products.Five.browser.pagetemplatefile
* Products.Five.browser.metaconfigure
- [_] zope.app.publication
o ZPublisher.BaseRequest
......
......@@ -11,6 +11,9 @@ Trunk (unreleased)
Restructuring
+++++++++++++
- Removed all use of ``zope.app.pagetemplate`` by cloning / simplifying
client code.
- Use ``zope.pagetemplate.engine`` instead of ``zope.app.pagetemplate.engine``.
(update to versions 3.5.0 and 3.7.0, respectively, along with version 3.8.1
of ``zope.app.publisher``).
......
......@@ -22,15 +22,17 @@ import os
from inspect import ismethod
from zope import component
from zope.interface import implements
from zope.interface import Interface
from zope.component.zcml import handler
from zope.component.interface import provideInterface
from zope.configuration.exceptions import ConfigurationError
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.publisher.interfaces import NotFound
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
from zope.publisher.interfaces.browser import IBrowserPublisher
from zope.publisher.interfaces.browser import IBrowserRequest
import zope.app.publisher.browser.viewmeta
import zope.app.pagetemplate.simpleviewclass
from zope.app.publisher.browser.viewmeta import providesCallable
from zope.app.publisher.browser.viewmeta import _handle_menu
from zope.app.publisher.browser.viewmeta import _handle_for
......@@ -405,9 +407,24 @@ class ViewMixinForAttributes(BrowserView,
def __call__(self):
return getattr(self, self.__page_attribute__)
class ViewMixinForTemplates(BrowserView,
zope.app.pagetemplate.simpleviewclass.simple):
pass
class ViewMixinForTemplates(BrowserView):
# Cloned from zope.app.pagetemplate.simpleviewclass.simple
implements(IBrowserPublisher)
def browserDefault(self, request):
return self, ()
def publishTraverse(self, request, name):
if name == 'index.html':
return self.index
raise NotFound(self, name, request)
def __getitem__(self, name):
return self.index.macros[name]
def __call__(self, *args, **kw):
return self.index(*args, **kw)
def makeClassForTemplate(filename, globals=None, used_for=None,
bases=(), cdict=None, name=u''):
......
......@@ -16,7 +16,9 @@
$Id$
"""
from os.path import basename
from zope.app.pagetemplate import viewpagetemplatefile
from zope.component import getMultiAdapter
from zope.pagetemplate.pagetemplatefile import PageTemplateFile
from zope.pagetemplate.engine import TrustedAppPT
from Acquisition import aq_get
from AccessControl import getSecurityManager
......@@ -29,9 +31,14 @@ _engine = createTrustedZopeEngine()
def getEngine():
return _engine
class ViewPageTemplateFile(viewpagetemplatefile.ViewPageTemplateFile):
class ViewPageTemplateFile(TrustedAppPT, PageTemplateFile):
"""Page Template used as class variable of views defined as Python classes.
"""
def __init__(self, filename, _prefix=None, content_type=None):
_prefix = self.get_path_from_prefix(_prefix)
super(ViewPageTemplateFile, self).__init__(filename, _prefix)
if content_type is not None:
self.content_type = content_type
def getId(self):
return basename(self.filename)
......@@ -61,17 +68,20 @@ class ViewPageTemplateFile(viewpagetemplatefile.ViewPageTemplateFile):
return getEngine()
def pt_getContext(self, instance, request, **kw):
context = super(ViewPageTemplateFile, self).pt_getContext(
instance, request, **kw)
namespace = super(ViewPageTemplateFile, self).pt_getContext(**kw)
namespace['request'] = request
namespace['view'] = instance
namespace['context'] = context = instance.context
namespace['views'] = ViewMapper(context, request)
# get the root
obj = context['context']
obj = context
root = None
meth = aq_get(obj, 'getPhysicalRoot', None)
if meth is not None:
root = meth()
context.update(here=obj,
namespace.update(here=obj,
# philiKON thinks container should be the view,
# but BBB is more important than aesthetics.
container=obj,
......@@ -80,22 +90,47 @@ class ViewPageTemplateFile(viewpagetemplatefile.ViewPageTemplateFile):
traverse_subpath=[], # BBB, never really worked
user = getSecurityManager().getUser()
)
return context
return namespace
def __get__(self, instance, type):
return BoundPageTemplate(self, instance)
class ViewMapper(object):
def __init__(self, ob, request):
self.ob = ob
self.request = request
def __getitem__(self, name):
return getMultiAdapter((self.ob, self.request), name=name)
# When a view's template is accessed e.g. as template.view, a
# BoundPageTemplate object is retured. For BBB reasons, it needs to
# support the aq_* methods and attributes known from Acquisition. For
# that it also needs to be locatable thru __parent__.
class BoundPageTemplate(viewpagetemplatefile.BoundPageTemplate,
AcquisitionBBB):
class BoundPageTemplate(AcquisitionBBB):
def __init__(self, pt, ob):
object.__setattr__(self, 'im_func', pt)
object.__setattr__(self, 'im_self', ob)
macros = property(lambda self: self.im_func.macros)
filename = property(lambda self: self.im_func.filename)
__parent__ = property(lambda self: self.im_self)
def __call__(self, *args, **kw):
if self.im_self is None:
im_self, args = args[0], args[1:]
else:
im_self = self.im_self
return self.im_func(im_self, *args, **kw)
def __setattr__(self, name, v):
raise AttributeError("Can't set attribute", name)
def __repr__(self):
return "<BoundPageTemplateFile of %r>" % self.im_self
# BBB
ZopeTwoPageTemplateFile = ViewPageTemplateFile
......@@ -176,9 +176,6 @@ ViewPageTemplateFile's take arbitrary keyword arguments:
Passing in an argument called instance was supported by the old Five version
of ViewPageTemplateFile, so we still need to support it.
In the zope.app.pagetemplate version, the first required argument is called
instance, though.
>>> print template(instance='allowed')
<p>The falcon has taken flight</p>
......
import unittest
class ViewMixinForTemplatesTests(unittest.TestCase):
def _getTargetClass(self):
from Products.Five.browser.metaconfigure import ViewMixinForTemplates
return ViewMixinForTemplates
def _makeOne(self, context=None, request=None):
if context is None:
context = DummyContext()
if request is None:
request = DummyRequest()
return self._getTargetClass()(context, request)
def test_class_conforms_to_IBrowserPublisher(self):
from zope.interface.verify import verifyClass
from zope.publisher.interfaces.browser import IBrowserPublisher
verifyClass(IBrowserPublisher, self._getTargetClass())
def test_browserDefault(self):
request = DummyRequest()
view = self._makeOne(request=request)
self.assertEqual(view.browserDefault(request), (view, ()))
def test_publishTraverse_not_index_raises_NotFound(self):
from zope.publisher.interfaces import NotFound
request = DummyRequest()
view = self._makeOne(request=request)
self.assertRaises(NotFound, view.publishTraverse, request, 'nonesuch')
def test_publishTraverse_w_index_returns_index(self):
request = DummyRequest()
view = self._makeOne(request=request)
index = view.index = DummyTemplate()
self.failUnless(view.publishTraverse(request, 'index.html') is index)
def test___getitem___uses_index_macros(self):
view = self._makeOne()
view.index = index = DummyTemplate()
index.macros = {}
index.macros['aaa'] = aaa = object()
self.failUnless(view['aaa'] is aaa)
def test___call___no_args_no_kw(self):
view = self._makeOne()
view.index = index = DummyTemplate()
result = view()
self.failUnless(result is index)
self.assertEqual(index._called_with, ((), {}))
def test___call___w_args_no_kw(self):
view = self._makeOne()
view.index = index = DummyTemplate()
result = view('abc')
self.failUnless(result is index)
self.assertEqual(index._called_with, (('abc',), {}))
def test___call___no_args_w_kw(self):
view = self._makeOne()
view.index = index = DummyTemplate()
result = view(foo='bar')
self.failUnless(result is index)
self.assertEqual(index._called_with, ((), {'foo': 'bar'}))
def test___call___no_args_no_kw(self):
view = self._makeOne()
view.index = index = DummyTemplate()
result = view('abc', foo='bar')
self.failUnless(result is index)
self.assertEqual(index._called_with, (('abc',), {'foo': 'bar'}))
class DummyContext:
pass
class DummyRequest:
pass
class DummyTemplate:
def __call__(self, *args, **kw):
self._called_with = (args, kw)
return self
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(ViewMixinForTemplatesTests),
))
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment