[Zope-Checkins]
SVN: Zope/branches/philikon-aq/lib/python/ZPublisher/
Make mapply() support objects of the form
Philipp von Weitershausen
philikon at philikon.de
Mon Jul 30 16:59:22 EDT 2007
Log message for revision 78481:
Make mapply() support objects of the form
class Foo:
__call__ = SomeCallableObject()
This is very useful for Zope 3 templates where this paradigm is used
all over the place. In fact, mapply simply uses this part of Zope 3's
__call__ finding logic. (I actually wish we could simply switch over to
Zope 3's mapply, but the call signatures aren't the same. Sigh.)
Changed:
U Zope/branches/philikon-aq/lib/python/ZPublisher/mapply.py
A Zope/branches/philikon-aq/lib/python/ZPublisher/tests/test_mapply.py
-=-
Modified: Zope/branches/philikon-aq/lib/python/ZPublisher/mapply.py
===================================================================
--- Zope/branches/philikon-aq/lib/python/ZPublisher/mapply.py 2007-07-30 19:36:16 UTC (rev 78480)
+++ Zope/branches/philikon-aq/lib/python/ZPublisher/mapply.py 2007-07-30 20:59:22 UTC (rev 78481)
@@ -12,6 +12,7 @@
##############################################################################
"""Provide an apply-like facility that works with any mapping object
"""
+import zope.publisher.publish
def default_call_object(object, args, context):
result=object(*args) # Type s<cr> to step into published object.
@@ -39,28 +40,16 @@
if hasattr(object,'__bases__'):
f, names, defaults = handle_class(object, context)
else:
- f=object
- im=0
- if hasattr(f, 'im_func'):
- im=1
- elif not hasattr(f,'func_defaults'):
- if hasattr(f, '__call__'):
- f=f.__call__
- if hasattr(f, 'im_func'):
- im=1
- elif not hasattr(f,'func_defaults') and maybe: return object
- elif maybe: return object
+ try:
+ f, count = zope.publisher.publish.unwrapMethod(object)
+ except TypeError:
+ if maybe:
+ return object
+ raise
+ code = f.func_code
+ defaults = f.func_defaults
+ names = code.co_varnames[count:code.co_argcount]
- if im:
- f=f.im_func
- c=f.func_code
- defaults=f.func_defaults
- names=c.co_varnames[1:c.co_argcount]
- else:
- defaults=f.func_defaults
- c=f.func_code
- names=c.co_varnames[:c.co_argcount]
-
nargs=len(names)
if positional:
positional=list(positional)
Added: Zope/branches/philikon-aq/lib/python/ZPublisher/tests/test_mapply.py
===================================================================
--- Zope/branches/philikon-aq/lib/python/ZPublisher/tests/test_mapply.py (rev 0)
+++ Zope/branches/philikon-aq/lib/python/ZPublisher/tests/test_mapply.py 2007-07-30 20:59:22 UTC (rev 78481)
@@ -0,0 +1,98 @@
+##############################################################################
+#
+# Copyright (c) 2007 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 mapply() function
+"""
+import unittest
+import ExtensionClass
+import Acquisition
+from ZPublisher.mapply import mapply
+
+class MapplyTests(unittest.TestCase):
+
+ def testMethod(self):
+ def compute(a,b,c=4):
+ return '%d%d%d' % (a, b, c)
+ values = {'a':2, 'b':3, 'c':5}
+ v = mapply(compute, (), values)
+ self.failUnlessEqual(v, '235')
+
+ v = mapply(compute, (7,), values)
+ self.failUnlessEqual(v, '735')
+
+ def testClass(self):
+ values = {'a':2, 'b':3, 'c':5}
+ class c(object):
+ a = 3
+ def __call__(self, b, c=4):
+ return '%d%d%d' % (self.a, b, c)
+ compute = __call__
+ cc = c()
+ v = mapply(cc, (), values)
+ self.failUnlessEqual(v, '335')
+
+ del values['c']
+ v = mapply(cc.compute, (), values)
+ self.failUnlessEqual(v, '334')
+
+ class c2:
+ """Must be a classic class."""
+
+ c2inst = c2()
+ c2inst.__call__ = cc
+ v = mapply(c2inst, (), values)
+ self.failUnlessEqual(v, '334')
+
+ def testObjectWithCall(self):
+ # Make sure that the __call__ of an object can also be another
+ # callable object. mapply will do the right thing and
+ # recursive look for __call__ attributes until it finds an
+ # actual method:
+
+ class CallableObject:
+ def __call__(self, a, b):
+ return '%s%s' % (a, b)
+
+ class Container:
+ __call__ = CallableObject()
+
+ v = mapply(Container(), (8, 3), {})
+ self.assertEqual(v, '83')
+
+ def testUncallableObject(self):
+ # Normally, mapply will raise a TypeError if it encounters an
+ # uncallable object (e.g. an interger ;))
+ self.assertRaises(TypeError, mapply, 2, (), {})
+
+ # Unless you enable the 'maybe' flag, in which case it will
+ # only maybe call the object
+ self.assertEqual(mapply(2, (), {}, maybe=True), 2)
+
+ def testNoCallButAcquisition(self):
+ # Make sure that mapply won't erroneously walk up the
+ # Acquisition chain when looking for __call__ attributes:
+
+ class Root(ExtensionClass.Base):
+ def __call__(self):
+ return 'The root __call__'
+
+ class NoCallButAcquisition(Acquisition.Implicit):
+ pass
+
+ ob = NoCallButAcquisition().__of__(Root())
+ self.assertRaises(TypeError, mapply, ob, (), {})
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(MapplyTests))
+ return suite
Property changes on: Zope/branches/philikon-aq/lib/python/ZPublisher/tests/test_mapply.py
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the Zope-Checkins
mailing list