[Zope-Checkins] SVN: Zope/trunk/ Remove all use of ``zope.app.pagetemplate`` by cloning / simplifying code.

Tres Seaver tseaver at palladion.com
Mon May 25 21:32:42 EDT 2009


Log message for revision 100383:
  Remove all use of ``zope.app.pagetemplate`` by cloning / simplifying code.
  
  o Added tests for previously-untested clients.
  

Changed:
  U   Zope/trunk/ZOPE_APP_DEPENDENCIES.rst
  U   Zope/trunk/doc/CHANGES.rst
  U   Zope/trunk/src/Products/Five/browser/metaconfigure.py
  U   Zope/trunk/src/Products/Five/browser/pagetemplatefile.py
  U   Zope/trunk/src/Products/Five/browser/tests/aqlegacy_ftest.txt
  A   Zope/trunk/src/Products/Five/browser/tests/test_metaconfigure.py
  A   Zope/trunk/src/Products/Five/browser/tests/test_pagetemplatefile.py

-=-
Modified: Zope/trunk/ZOPE_APP_DEPENDENCIES.rst
===================================================================
--- Zope/trunk/ZOPE_APP_DEPENDENCIES.rst	2009-05-26 00:06:45 UTC (rev 100382)
+++ Zope/trunk/ZOPE_APP_DEPENDENCIES.rst	2009-05-26 01:32:41 UTC (rev 100383)
@@ -18,10 +18,10 @@
 - [_] 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

Modified: Zope/trunk/doc/CHANGES.rst
===================================================================
--- Zope/trunk/doc/CHANGES.rst	2009-05-26 00:06:45 UTC (rev 100382)
+++ Zope/trunk/doc/CHANGES.rst	2009-05-26 01:32:41 UTC (rev 100383)
@@ -11,6 +11,9 @@
 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``).

Modified: Zope/trunk/src/Products/Five/browser/metaconfigure.py
===================================================================
--- Zope/trunk/src/Products/Five/browser/metaconfigure.py	2009-05-26 00:06:45 UTC (rev 100382)
+++ Zope/trunk/src/Products/Five/browser/metaconfigure.py	2009-05-26 01:32:41 UTC (rev 100383)
@@ -22,15 +22,17 @@
 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 import NotFound
+from zope.publisher.interfaces.browser import IDefaultBrowserLayer
+from zope.publisher.interfaces.browser import IBrowserPublisher
 from zope.publisher.interfaces.browser import IBrowserRequest
-from zope.publisher.interfaces.browser import IDefaultBrowserLayer
 
 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,10 +407,25 @@
     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''):
     # XXX needs to deal with security from the bases?

Modified: Zope/trunk/src/Products/Five/browser/pagetemplatefile.py
===================================================================
--- Zope/trunk/src/Products/Five/browser/pagetemplatefile.py	2009-05-26 00:06:45 UTC (rev 100382)
+++ Zope/trunk/src/Products/Five/browser/pagetemplatefile.py	2009-05-26 01:32:41 UTC (rev 100383)
@@ -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 @@
 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,41 +68,69 @@
         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,
-                       # philiKON thinks container should be the view,
-                       # but BBB is more important than aesthetics.
-                       container=obj,
-                       root=root,
-                       modules=SecureModuleImporter,
-                       traverse_subpath=[],  # BBB, never really worked
-                       user = getSecurityManager().getUser()
-                       )
-        return context
+        namespace.update(here=obj,
+                         # philiKON thinks container should be the view,
+                         # but BBB is more important than aesthetics.
+                         container=obj,
+                         root=root,
+                         modules=SecureModuleImporter,
+                         traverse_subpath=[],  # BBB, never really worked
+                         user = getSecurityManager().getUser()
+                        )
+        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

Modified: Zope/trunk/src/Products/Five/browser/tests/aqlegacy_ftest.txt
===================================================================
--- Zope/trunk/src/Products/Five/browser/tests/aqlegacy_ftest.txt	2009-05-26 00:06:45 UTC (rev 100382)
+++ Zope/trunk/src/Products/Five/browser/tests/aqlegacy_ftest.txt	2009-05-26 01:32:41 UTC (rev 100383)
@@ -176,9 +176,6 @@
 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>
 

Added: Zope/trunk/src/Products/Five/browser/tests/test_metaconfigure.py
===================================================================
--- Zope/trunk/src/Products/Five/browser/tests/test_metaconfigure.py	                        (rev 0)
+++ Zope/trunk/src/Products/Five/browser/tests/test_metaconfigure.py	2009-05-26 01:32:41 UTC (rev 100383)
@@ -0,0 +1,88 @@
+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),
+    ))

Added: Zope/trunk/src/Products/Five/browser/tests/test_pagetemplatefile.py
===================================================================
--- Zope/trunk/src/Products/Five/browser/tests/test_pagetemplatefile.py	                        (rev 0)
+++ Zope/trunk/src/Products/Five/browser/tests/test_pagetemplatefile.py	2009-05-26 01:32:41 UTC (rev 100383)
@@ -0,0 +1,315 @@
+import unittest
+
+class ViewPageTemplateFileTests(unittest.TestCase):
+
+    def setUp(self):
+        from AccessControl.SecurityManagement import noSecurityManager
+        noSecurityManager()
+
+    def tearDown(self):
+        from AccessControl.SecurityManagement import noSecurityManager
+        noSecurityManager()
+
+    def _getTargetClass(self):
+        from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+        return ViewPageTemplateFile
+
+    def _makeOne(self, filename, _prefix=None, content_type=None):
+        return self._getTargetClass()(filename, _prefix, content_type)
+
+    def _makeView(self, context=None, request=None):
+        if context is None:
+            context = DummyContext()
+        if request is None:
+            request = DummyRequest()
+        return DummyView(context, request)
+
+    def test_getId_simple_name(self):
+        vptf = self._makeOne('seagull.pt')
+        self.assertEqual(vptf.getId(), 'seagull.pt')
+        self.assertEqual(vptf.id, 'seagull.pt')
+
+    def test_getId_with_path(self):
+        vptf = self._makeOne('pages/dirpage1.pt')
+        self.assertEqual(vptf.id, 'dirpage1.pt')
+
+    def test_pt_getEngine(self):
+        from zope.tales.expressions import DeferExpr
+        from zope.tales.expressions import NotExpr
+        from zope.tales.expressions import PathExpr
+        from zope.tales.expressions import StringExpr
+        from zope.tales.expressions import Undefs
+        from zope.tales.pythonexpr import PythonExpr
+        from zope.contentprovider.tales import TALESProviderExpression
+        from Products.PageTemplates.DeferExpr import LazyExpr
+        from Products.PageTemplates.Expressions import ZopePathExpr
+        from Products.PageTemplates.Expressions import SecureModuleImporter
+
+        vptf = self._makeOne('seagull.pt')
+        engine = vptf.pt_getEngine()
+        self.assertEqual(engine.types['standard'], ZopePathExpr)
+        self.assertEqual(engine.types['path'], ZopePathExpr)
+        self.assertEqual(engine.types['exists'], ZopePathExpr)
+        self.assertEqual(engine.types['nocall'], ZopePathExpr)
+        self.assertEqual(engine.types['string'], StringExpr)
+        self.assertEqual(engine.types['python'], PythonExpr)
+        self.assertEqual(engine.types['not'], NotExpr)
+        self.assertEqual(engine.types['defer'], DeferExpr)
+        self.assertEqual(engine.types['lazy'], LazyExpr)
+        self.assertEqual(engine.types['provider'], TALESProviderExpression)
+        self.assertEqual(engine.base_names['modules'], SecureModuleImporter)
+
+    def test_pt_getContext_no_kw_no_physicalRoot(self):
+        from Products.Five.browser.pagetemplatefile import ViewMapper
+        from Products.PageTemplates.Expressions import SecureModuleImporter
+        from AccessControl.SecurityManagement import newSecurityManager
+        newSecurityManager(None, DummyUser('a_user'))
+        context = DummyContext()
+        request = DummyRequest()
+        view = self._makeView(context, request)
+        vptf = self._makeOne('seagull.pt')
+        namespace = vptf.pt_getContext(view, request)
+        self.failUnless(namespace['context'] is context)
+        self.failUnless(namespace['request'] is request)
+        views = namespace['views']
+        self.failUnless(isinstance(views, ViewMapper))
+        self.assertEqual(views.ob, context)
+        self.assertEqual(views.request, request)
+        self.failUnless(namespace['here'] is context)
+        self.failUnless(namespace['container'] is context)
+        self.failUnless(namespace['root'] is None)
+        modules = namespace['modules']
+        self.failUnless(modules is SecureModuleImporter)
+        self.assertEqual(namespace['traverse_subpath'], [])
+        self.assertEqual(namespace['user'].getId(), 'a_user')
+
+    def test_pt_getContext_w_physicalRoot(self):
+        from Products.Five.browser.pagetemplatefile import ViewMapper
+        from Products.PageTemplates.Expressions import SecureModuleImporter
+        from AccessControl.SecurityManagement import newSecurityManager
+        newSecurityManager(None, DummyUser('a_user'))
+        context = DummyContext()
+        root = DummyContext()
+        context.getPhysicalRoot = lambda: root
+        request = DummyRequest()
+        view = self._makeView(context, request)
+        vptf = self._makeOne('seagull.pt')
+        namespace = vptf.pt_getContext(view, request)
+        self.failUnless(namespace['root'] is root)
+
+    def test_pt_getContext_w_ignored_kw(self):
+        from Products.Five.browser.pagetemplatefile import ViewMapper
+        from Products.PageTemplates.Expressions import SecureModuleImporter
+        from AccessControl.SecurityManagement import newSecurityManager
+        newSecurityManager(None, DummyUser('a_user'))
+        context = DummyContext()
+        request = DummyRequest()
+        view = self._makeView(context, request)
+        vptf = self._makeOne('seagull.pt')
+        namespace = vptf.pt_getContext(view, request, foo='bar')
+        self.failIf('foo' in namespace)
+        self.failIf('foo' in namespace['options'])
+
+    def test_pt_getContext_w_args_kw(self):
+        from Products.Five.browser.pagetemplatefile import ViewMapper
+        from Products.PageTemplates.Expressions import SecureModuleImporter
+        from AccessControl.SecurityManagement import newSecurityManager
+        newSecurityManager(None, DummyUser('a_user'))
+        context = DummyContext()
+        request = DummyRequest()
+        view = self._makeView(context, request)
+        vptf = self._makeOne('seagull.pt')
+        namespace = vptf.pt_getContext(view, request, args=('bar', 'baz'))
+        self.assertEqual(namespace['args'], ('bar', 'baz'))
+
+    def test_pt_getContext_w_options_kw(self):
+        from Products.Five.browser.pagetemplatefile import ViewMapper
+        from Products.PageTemplates.Expressions import SecureModuleImporter
+        from AccessControl.SecurityManagement import newSecurityManager
+        newSecurityManager(None, DummyUser('a_user'))
+        context = DummyContext()
+        request = DummyRequest()
+        view = self._makeView(context, request)
+        vptf = self._makeOne('seagull.pt')
+        namespace = vptf.pt_getContext(view, request, options={'bar': 'baz'})
+        self.assertEqual(namespace['options'], {'bar': 'baz'})
+
+    def test___call___no_previous_content_type(self):
+        context = DummyContext()
+        request = DummyRequest()
+        response = request.response = DummyResponse()
+        view = self._makeView(context, request)
+        vptf = self._makeOne('pages/dirpage1.pt')
+        body = vptf(view)
+        self.assertEqual(body, DIRPAGE1)
+        self.assertEqual(response._headers['Content-Type'], 'text/html')
+
+    def test___call___w_previous_content_type(self):
+        context = DummyContext()
+        request = DummyRequest()
+        response = request.response = DummyResponse(
+                                        {'Content-Type': 'text/xhtml'})
+        view = self._makeView(context, request)
+        vptf = self._makeOne('pages/dirpage1.pt')
+        body = vptf(view)
+        self.assertEqual(response._headers['Content-Type'], 'text/xhtml')
+
+    def test___get___(self):
+        from Products.Five.browser.pagetemplatefile import BoundPageTemplate
+        template = self._makeOne('pages/dirpage1.pt')
+        class Foo:
+            def __init__(self, context, request):
+                self.context = context
+                self.request = request
+            bar = template
+        context = DummyContext()
+        request = DummyRequest()
+        foo = Foo(context, request)
+        bound = foo.bar
+        self.failUnless(isinstance(bound, BoundPageTemplate))
+        self.failUnless(bound.im_func is template)
+        self.failUnless(bound.im_self is foo)
+
+class ViewMapperTests(unittest.TestCase):
+
+    def setUp(self):
+        from zope.component.testing import setUp
+        setUp()
+
+    def tearDown(self):
+        from zope.component.testing import tearDown
+        tearDown()
+
+    def _getTargetClass(self):
+        from Products.Five.browser.pagetemplatefile import ViewMapper
+        return ViewMapper
+
+    def _makeOne(self, ob=None, request=None):
+        if ob is None:
+            ob = DummyContext()
+        if request is None:
+            request = DummyRequest()
+        return self._getTargetClass()(ob, request)
+
+    def test___getitem___miss(self):
+        from zope.component import ComponentLookupError
+        mapper = self._makeOne()
+        self.assertRaises(ComponentLookupError, mapper.__getitem__, 'nonesuch')
+
+    def test___getitem___hit(self):
+        from zope.interface import Interface
+        from zope.component import provideAdapter
+        def _adapt(context, request):
+            return self
+        provideAdapter(_adapt, (None, None), Interface, name='test')
+        mapper = self._makeOne()
+        self.failUnless(mapper['test'] is self)
+
+_marker = object()
+
+class BoundPageTemplateTests(unittest.TestCase):
+
+    def _getTargetClass(self):
+        from Products.Five.browser.pagetemplatefile import BoundPageTemplate
+        return BoundPageTemplate
+
+    def _makeOne(self, pt=_marker, ob=_marker):
+        if pt is _marker:
+            pt = DummyTemplate()
+        if ob is _marker:
+            ob = DummyContext()
+        return self._getTargetClass()(pt, ob)
+
+    def test___init__(self):
+        pt = DummyTemplate({'foo': 'bar'})
+        ob = DummyContext()
+        bpt = self._makeOne(pt, ob)
+        self.failUnless(bpt.im_func is pt)
+        self.failUnless(bpt.im_self is ob)
+        self.failUnless(bpt.__parent__ is ob)
+        self.assertEqual(bpt.macros['foo'], 'bar')
+        self.assertEqual(bpt.filename, 'dummy.pt')
+
+    def test___setattr___raises(self):
+        bpt = self._makeOne()
+        try:
+            bpt.foo = 'bar'
+        except AttributeError:
+            pass
+        else:
+            self.fail('Attribute assigned')
+
+    def test___call___w_real_im_self_no_args_no_kw(self):
+        pt = DummyTemplate()
+        ob = DummyContext()
+        bpt = self._makeOne(pt, ob)
+        rendered = bpt()
+        self.assertEqual(rendered, '<h1>Dummy</h1>')
+        self.assertEqual(pt._called_with, (ob, (), {}))
+
+    def test___call___w_real_im_self_w_args_w_kw(self):
+        pt = DummyTemplate()
+        ob = DummyContext()
+        bpt = self._makeOne(pt, ob)
+        rendered = bpt('abc', foo='bar')
+        self.assertEqual(rendered, '<h1>Dummy</h1>')
+        self.assertEqual(pt._called_with, (ob, ('abc',), {'foo': 'bar'}))
+
+    def test___call___wo_real_im_self_w_args_w_kw(self):
+        pt = DummyTemplate()
+        bpt = self._makeOne(pt, None)
+        rendered = bpt('abc', 'def', foo='bar')
+        self.assertEqual(rendered, '<h1>Dummy</h1>')
+        self.assertEqual(pt._called_with, ('abc', ('def',), {'foo': 'bar'}))
+
+DIRPAGE1 = """\
+<html>
+<p>This is page 1</p>
+</html>
+"""
+
+class DummyContext:
+    pass
+
+class DummyRequest:
+    debug = object()
+
+class DummyResponse:
+    def __init__(self, headers=None):
+        if headers is None:
+            headers = {}
+        self._headers = headers
+
+    def getHeader(self, name):
+        return self._headers.get(name)
+
+    def setHeader(self, name, value):
+        self._headers[name] = value
+
+class DummyTemplate:
+    filename = 'dummy.pt'
+    def __init__(self, macros=None):
+        if macros is None:
+            macros = {}
+        self.macros = macros
+    def __call__(self, im_self, *args, **kw):
+        self._called_with = (im_self, args, kw)
+        return '<h1>Dummy</h1>'
+
+class DummyView:
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+class DummyUser:
+    def __init__(self, name):
+        self._name = name
+    def getId(self):
+        return self._name
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(ViewPageTemplateFileTests),
+        unittest.makeSuite(ViewMapperTests),
+        unittest.makeSuite(BoundPageTemplateTests),
+    ))



More information about the Zope-Checkins mailing list