[Zope-Checkins] SVN: Products.Five/branches/1.5/ Backport fix for
argument signature of synthesized '__call__'.
Tres Seaver
tseaver at palladion.com
Wed Oct 4 12:09:30 EDT 2006
Log message for revision 70531:
Backport fix for argument signature of synthesized '__call__'.
Changed:
U Products.Five/branches/1.5/CHANGES.txt
U Products.Five/branches/1.5/browser/metaconfigure.py
A Products.Five/branches/1.5/browser/tests/classes.py
U Products.Five/branches/1.5/browser/tests/test_defaultview.py
-=-
Modified: Products.Five/branches/1.5/CHANGES.txt
===================================================================
--- Products.Five/branches/1.5/CHANGES.txt 2006-10-04 15:18:44 UTC (rev 70530)
+++ Products.Five/branches/1.5/CHANGES.txt 2006-10-04 16:09:30 UTC (rev 70531)
@@ -3,8 +3,12 @@
============
Five 1.5.1 (unreleased)
-=====================
+=======================
+* Made the __call__ method of ViewMixinForAttributes have the same signature
+ as the original attribute. This aids some pathological request parameter
+ marshalling.
+
* Fixed #2168: Missing import
Five 1.5 (2006-08-13)
Modified: Products.Five/branches/1.5/browser/metaconfigure.py
===================================================================
--- Products.Five/branches/1.5/browser/metaconfigure.py 2006-10-04 15:18:44 UTC (rev 70530)
+++ Products.Five/branches/1.5/browser/metaconfigure.py 2006-10-04 16:09:30 UTC (rev 70531)
@@ -386,10 +386,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):
Copied: Products.Five/branches/1.5/browser/tests/classes.py (from rev 70530, Products.Five/trunk/browser/tests/classes.py)
Modified: Products.Five/branches/1.5/browser/tests/test_defaultview.py
===================================================================
--- Products.Five/branches/1.5/browser/tests/test_defaultview.py 2006-10-04 15:18:44 UTC (rev 70530)
+++ Products.Five/branches/1.5/browser/tests/test_defaultview.py 2006-10-04 16:09:30 UTC (rev 70531)
@@ -114,6 +114,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