[Zope-Checkins] SVN: Products.Five/branches/1.3/ Backporting ree's fix to 1.3 branch

Alec Mitchell apm13 at columbia.edu
Tue Aug 29 10:48:03 EDT 2006


Log message for revision 69843:
  Backporting ree's fix to 1.3 branch
  

Changed:
  U   Products.Five/branches/1.3/CHANGES.txt
  U   Products.Five/branches/1.3/browser/metaconfigure.py
  A   Products.Five/branches/1.3/browser/tests/classes.py
  U   Products.Five/branches/1.3/browser/tests/test_defaultview.py

-=-
Modified: Products.Five/branches/1.3/CHANGES.txt
===================================================================
--- Products.Five/branches/1.3/CHANGES.txt	2006-08-29 14:47:07 UTC (rev 69842)
+++ Products.Five/branches/1.3/CHANGES.txt	2006-08-29 14:48:01 UTC (rev 69843)
@@ -8,6 +8,10 @@
 Bugfixes
 --------
 
+* Made the __call__ method of ViewMixinForAttributes have the same signature
+  as the original attribute.  This aids some pathological request parameter
+  marshalling.
+
 * Allow multiple uses of the <class>/<content> directive.
 
 * Fix problem with WebDAV/HEAD requests due to new traversal order.

Modified: Products.Five/branches/1.3/browser/metaconfigure.py
===================================================================
--- Products.Five/branches/1.3/browser/metaconfigure.py	2006-08-29 14:47:07 UTC (rev 69842)
+++ Products.Five/branches/1.3/browser/metaconfigure.py	2006-08-29 14:48:01 UTC (rev 69843)
@@ -382,10 +382,7 @@
     # this is technically not needed because ZPublisher finds our
     # attribute through __browser_default__; but we also want to be
     # able to call pages from python modules, PythonScripts or ZPT
-    def __call__(self, *args, **kw):
-        attr = self.__page_attribute__
-        meth = getattr(self, attr)
-        return meth(*args, **kw)
+    __call__ = property(lambda self: getattr(self, self.__page_attribute__))
 
 class ViewMixinForTemplates(BrowserView):
 

Added: Products.Five/branches/1.3/browser/tests/classes.py
===================================================================
--- Products.Five/branches/1.3/browser/tests/classes.py	2006-08-29 14:47:07 UTC (rev 69842)
+++ Products.Five/branches/1.3/browser/tests/classes.py	2006-08-29 14:48:01 UTC (rev 69843)
@@ -0,0 +1,31 @@
+##############################################################################
+#
+# Copyright (c) 2004, 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Test fixtures
+"""
+from zope.interface import Interface, implements
+from Products.Five import BrowserView
+
+class IOne(Interface):
+    """This is a Zope 3 interface.
+    """
+
+class One(object):
+    'A class'
+    implements(IOne)
+
+class ViewOne(BrowserView):
+    'Yet another class'
+
+    def my_method(self, arg1, arg2, kw1=None, kw2='D'):
+        print "CALLED %s %s %s %s" % (arg1, arg2, kw1, kw2)

Modified: Products.Five/branches/1.3/browser/tests/test_defaultview.py
===================================================================
--- Products.Five/branches/1.3/browser/tests/test_defaultview.py	2006-08-29 14:47:07 UTC (rev 69842)
+++ Products.Five/branches/1.3/browser/tests/test_defaultview.py	2006-08-29 14:48:01 UTC (rev 69843)
@@ -83,6 +83,98 @@
       >>> tearDown()
     """
 
+def test_default_method_args_marshalling():
+    """\
+    Test the default call method of a view, with respect to possible
+    breakage of argument marshalling from other components
+
+    This is not directly a bug in Five, just a change that enables
+    components have simpler code to imitate ZPublisher's arguments
+    marshalling strategy on default view methods.
+
+    The ZPublisher marshalls arguments to called methods from the
+    request based on the method's signature. This however assumes
+    that it finds the real callable method. However in case of the
+    autogenerated __call__ method of a view, the real method is
+    wrapped. Although the publisher correctly handles this by
+    looking at the __browser_default__ and applying the request on
+    the real method, Plone's portal factory does not do this
+    correctly, thus causing these method calls fail with TypeError,
+    since no parameters will be marshalled to the browser default
+    methods if within the portal factory.
+
+    The applied fix changes the __call__ in such a way that it is
+    not wrapper any more, but yields the original callable instead.
+    This test simply checks that this is so, in other words this is
+    a check that would have failed with the original version.
+
+    First, we load the configuration file:
+
+      >>> import Products.Five.tests
+      >>> from Products.Five import zcml
+      >>> zcml.load_config('meta.zcml', Products.Five)
+      >>> zcml.load_config("permissions.zcml", Products.Five)
+      >>> zcml.load_config('directives.zcml', Products.Five.tests)
+
+    Define a view, with a single attribute and the name of the view
+    is the same as the attribute. Important is that we will use the
+    default browser view.
+
+      >>> zcml.load_string('''
+      ...   <configure xmlns="http://namespaces.zope.org/zope"
+      ...              xmlns:browser="http://namespaces.zope.org/browser">
+      ...        <browser:page
+      ...            for="Products.Five.browser.tests.classes.IOne"
+      ...            class="Products.Five.browser.tests.classes.ViewOne"
+      ...            attribute="my_method"
+      ...            name="my_method"
+      ...            permission="zope2.Public"
+      ...        />
+      ...   </configure>
+      ...   ''')
+
+    Create a context object and a request. Provide parameters on the
+    request.
+
+      >>> from Products.Five.browser.tests.classes import One
+      >>> context = One()
+      >>> from zope.publisher.browser import TestRequest
+      >>> request = TestRequest(form={'arg1': 'A', 'arg2': 'B', 'kw1': 'C'})
+
+    Create the view.
+
+      >>> from zope.component import getMultiAdapter
+      >>> from zope.interface import Interface
+      >>> view = getMultiAdapter((context, request), Interface, 'my_method')
+
+    Check that the __call__ method's signature equals to the real
+    method's signature. They both should yield the four parameters.
+
+      >>> def args(method):
+      ...     f = method.im_func
+      ...     c = f.func_code
+      ...     defaults = f.func_defaults
+      ...     names = c.co_varnames[1:c.co_argcount]
+      ...     return names
+      >>> args(view.my_method)
+      ('arg1', 'arg2', 'kw1', 'kw2')
+      >>> args(view.__call__)
+      ('arg1', 'arg2', 'kw1', 'kw2')
+
+    Finally, call the view's default method. Important is, if this
+    gives a TypeError then the portal factory will fail. This is in
+    effect the same as the previous argument check was.
+
+      >>> from ZPublisher.mapply import mapply
+      >>> mapply(view.__call__, (), request)
+      CALLED A B C D
+
+    Clean up adapter registry and others:
+
+      >>> from zope.testing.cleanup import cleanUp
+      >>> cleanUp()
+    """
+
 def test_suite():
     from Testing.ZopeTestCase import FunctionalDocTestSuite
     return FunctionalDocTestSuite()



More information about the Zope-Checkins mailing list