[z3-checkins] r5635 - in z3/Five/trunk: . doc tests tests/products/FiveTest

philikon at codespeak.net philikon at codespeak.net
Fri Jul 23 16:05:02 MEST 2004


Author: philikon
Date: Fri Jul 23 16:05:01 2004
New Revision: 5635

Added:
   z3/Five/trunk/tests/products/FiveTest/fancycontent.py
Modified:
   z3/Five/trunk/doc/TODO.txt
   z3/Five/trunk/fiveconfigure.py
   z3/Five/trunk/tests/products/FiveTest/__init__.py
   z3/Five/trunk/tests/products/FiveTest/browser.py
   z3/Five/trunk/tests/products/FiveTest/configure.zcml
   z3/Five/trunk/tests/products/FiveTest/interfaces.py
   z3/Five/trunk/tests/test_five.py
   z3/Five/trunk/viewable.py
Log:
Kill off two TODO items before the 0.1 release:

- Make five:viewable allow being called several times.  Once it
  is called for a class, or if the class inherits from Viewable
  directly, a marker, __five_viewable__ is put on the class
  which tells five:viewable to simply ignore the request.

- Support the coexisting with already existing __bobo_traverse__
  methods.  If five:viewable finds a class with such a method,
  it renames the method to __fallback_traverse__ and overwrites
  it with Viewable's __bobo_traverse__.  That way, Zope3-style
  views receive precedence over custom class view wirings.

  The default __fallback_traverse__ raises NotFound.


Modified: z3/Five/trunk/doc/TODO.txt
==============================================================================
--- z3/Five/trunk/doc/TODO.txt	(original)
+++ z3/Five/trunk/doc/TODO.txt	Fri Jul 23 16:05:01 2004
@@ -2,8 +2,6 @@
 TODO
 ====
 
-- make five:viewable support being called several times
-
 - allow Zope2 boilerplate context.registerClass be configured thru zcml
 
 - implement/register missing zope.app directives:
@@ -12,8 +10,6 @@
 
   * ...
 
-- support existing __bobo_traverse__ methods
-
 - secure page templates
 
 - now that we have zope:content, do we still need five:implements?

Modified: z3/Five/trunk/fiveconfigure.py
==============================================================================
--- z3/Five/trunk/fiveconfigure.py	(original)
+++ z3/Five/trunk/fiveconfigure.py	Fri Jul 23 16:05:01 2004
@@ -65,9 +65,21 @@
             )
 
 def classViewable(class_):
+    # if a class already has this attribute, it means it is either a
+    # subclass of api.Viewable or was already processed with this
+    # directive; in either case, do nothing...
+    if hasattr(class_, '__five_viewable__'):
+        return
+
     if hasattr(class_, '__bobo_traverse__'):
-        raise TypeError("__bobo_traverse already__ exists on %s" % class_)
+        # if there's an existing bobo_traverse hook already, use that
+        # as the traversal fallback method
+        setattr(class_, "__fallback_traverse__", class_.__bobo_traverse__)
+    else:
+        setattr(class_, "__fallback_traverse__", Viewable.__fallback_traverse__)
+
     setattr(class_, '__bobo_traverse__', Viewable.__bobo_traverse__)
+    setattr(class_, '__five_viewable__', True)
 
 def viewable(_context, class_):
     _context.action(

Modified: z3/Five/trunk/tests/products/FiveTest/__init__.py
==============================================================================
--- z3/Five/trunk/tests/products/FiveTest/__init__.py	(original)
+++ z3/Five/trunk/tests/products/FiveTest/__init__.py	Fri Jul 23 16:05:01 2004
@@ -1,5 +1,6 @@
 import Products
 import simplecontent
+import fancycontent
 
 def initialize(context):
 
@@ -8,3 +9,8 @@
         constructors = (simplecontent.manage_addSimpleContentForm,
                         simplecontent.manage_addSimpleContent),
         )
+
+    context.registerClass(
+	fancycontent.FancyContent,
+	constructors = (fancycontent.manage_addFancyContent,)
+	)

Modified: z3/Five/trunk/tests/products/FiveTest/browser.py
==============================================================================
--- z3/Five/trunk/tests/products/FiveTest/browser.py	(original)
+++ z3/Five/trunk/tests/products/FiveTest/browser.py	Fri Jul 23 16:05:01 2004
@@ -11,6 +11,12 @@
         """Docstring"""
         return "The mouse has been eaten by the eagle"
 
+class FancyContentView(BrowserView):
+    """Fancy, fancy stuff"""
+
+    def view(self):
+        return "Fancy, fancy"
+
 class CallableNoDocstring:
 
     def __call__(self):

Modified: z3/Five/trunk/tests/products/FiveTest/configure.zcml
==============================================================================
--- z3/Five/trunk/tests/products/FiveTest/configure.zcml	(original)
+++ z3/Five/trunk/tests/products/FiveTest/configure.zcml	Fri Jul 23 16:05:01 2004
@@ -2,6 +2,19 @@
            xmlns:browser="http://namespaces.zope.org/browser"
            xmlns:five="http://namespaces.zope.org/five">
 
+  <!-- this is a test whether five:viewable can be called more than
+       once on a class; SimpleContent inherits from api.Viewable, so
+       one directive suffices here -->
+
+  <five:viewable class=".simplecontent.SimpleContent" />
+
+
+  <!-- this tests whether five:viewable can be called on a class that
+       already provides __bobo_traverse__, such as our FancyContent -->
+
+  <five:viewable class=".fancycontent.FancyContent" />
+
+
   <adapter
     for=".interfaces.IAdaptable"
     provides=".interfaces.IAdapted"
@@ -17,6 +30,14 @@
     permission="zope2.ViewManagementScreens"
     />
 
+  <browser:page
+    for=".interfaces.IFancyContent"
+    class=".browser.FancyContentView"
+    attribute="view"
+    name="fancy"
+    permission="zope2.Public"
+    />
+
   <browser:pages
     for=".interfaces.ISimpleContent"
     class=".browser.NoDocstringView"

Added: z3/Five/trunk/tests/products/FiveTest/fancycontent.py
==============================================================================
--- (empty file)
+++ z3/Five/trunk/tests/products/FiveTest/fancycontent.py	Fri Jul 23 16:05:01 2004
@@ -0,0 +1,40 @@
+import Acquisition
+from AccessControl import ClassSecurityInfo
+from OFS.SimpleItem import SimpleItem
+from Globals import InitializeClass
+
+from zope.interface import implements
+from interfaces import IFancyContent
+
+class FancyAttribute(Acquisition.Explicit):
+    """Doc test fanatics"""
+
+    def __init__(self, name):
+        self.name = name
+
+    security = ClassSecurityInfo()
+
+    security.declarePublic('index_html')
+    def index_html(self, REQUEST):
+        """Doc test fanatics"""
+        return self.name
+
+InitializeClass(FancyAttribute)
+
+class FancyContent(SimpleItem):
+    """A class that already comes with its own __bobo_traverse__ handler.
+    Quite fancy indeed."""
+    implements(IFancyContent)
+
+    meta_type = "Fancy Content"
+    security = ClassSecurityInfo()
+
+    def __bobo_traverse__(self, REQUEST, name):
+        return FancyAttribute(name).__of__(self)
+
+InitializeClass(FancyContent)
+
+def manage_addFancyContent(self, id, REQUEST=None):
+    """Add the fancy fancy content."""
+    id = self._setObject(id, FancyContent(id))
+    return ''

Modified: z3/Five/trunk/tests/products/FiveTest/interfaces.py
==============================================================================
--- z3/Five/trunk/tests/products/FiveTest/interfaces.py	(original)
+++ z3/Five/trunk/tests/products/FiveTest/interfaces.py	Fri Jul 23 16:05:01 2004
@@ -26,3 +26,6 @@
 
 class ISimpleContent(Interface):
     pass
+
+class IFancyContent(Interface):
+    pass

Modified: z3/Five/trunk/tests/test_five.py
==============================================================================
--- z3/Five/trunk/tests/test_five.py	(original)
+++ z3/Five/trunk/tests/test_five.py	Fri Jul 23 16:05:01 2004
@@ -138,6 +138,22 @@
             response = self.publish('/test_folder_1_/testoid/%s' % view_name)
             self.assertEquals("No docstring", response.getBody())
 
+    def test_fallback_raises_notfound(self):
+        response = self.publish('/test_folder_1_/testoid/doesntexist')
+        self.assertEquals(404, response.getStatus())
+
+    def test_existing_bobo_traverse(self):
+        self.folder.manage_addProduct['FiveTest'].manage_addFancyContent(
+            'fancy')
+
+        # check if z3-based view lookup works
+        response = self.publish('/test_folder_1_/fancy/fancy')
+        self.assertEquals("Fancy, fancy", response.getBody())
+
+        # check if the old bobo_traverse method can still kick in
+        response = self.publish('/test_folder_1_/fancy/something-else')
+        self.assertEquals('something-else', response.getBody())
+
 def test_suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(FiveTestCase))

Modified: z3/Five/trunk/viewable.py
==============================================================================
--- z3/Five/trunk/viewable.py	(original)
+++ z3/Five/trunk/viewable.py	Fri Jul 23 16:05:01 2004
@@ -27,33 +27,38 @@
 class Viewable:
     """A mixin to make an object viewable using the Zope 3 system.
     """
+    __five_viewable__ = True
+
+    def __fallback_traverse__(self, REQUEST, name):
+        """Method hook for fallback traversal
+
+        This method is called by __bobo_traverse___ when Zope3-style
+        view lookup fails.  By default, we do what Zope 2 would do,
+        raise a NotFound error."""
+        try:
+            REQUEST.RESPONSE.notFoundError("%s " % name)
+        except AttributeError:
+            raise KeyError, name
+
     def __bobo_traverse__(self, REQUEST, name):
+        """Hook for Zope 2 traversal
+
+        This method is called by Zope 2's ZPublisher upon traversal.
+        It allows us to trick it into publishing Zope 3-style views.
+        """
+        if not IBrowserRequest.providedBy(REQUEST):
+            REQUEST = FakeRequest()
+        try:
+            return getView(self, name, REQUEST).__of__(self)
+        except ComponentLookupError:
+            pass
+        try:
+            return getattr(self, name)
+        except AttributeError:
+            pass
         try:
-            if not IBrowserRequest.providedBy(REQUEST):
-                REQUEST = FakeRequest()
-            try:
-                return getView(self, name, REQUEST).__of__(self)
-            except ComponentLookupError:
-                pass
-            try:
-                return getattr(self, name)
-            except AttributeError:
-                pass
-            try:
-                return self[name]
-            except (AttributeError, KeyError):
-                pass
-            # XXX not sure this is very useful
-            #method = REQUEST.get('REQUEST_METHOD', 'GET')
-            #if not method in ('GET', 'POST'):
-            #    return NullResource(self, name, REQUEST).__of__(self)
+            return self[name]
+        except (AttributeError, KeyError):
+            pass
 
-            # Waaa. See Application.py
-            try:
-                REQUEST.RESPONSE.notFoundError("%s " % name)
-            except AttributeError:
-                raise KeyError, name
-        except:
-            import traceback
-            traceback.print_exc()
-            raise
+        return self.__fallback_traverse__(REQUEST, name)


More information about the z3-checkins mailing list