[ZPatterns] Why is class_default_for_ method unbound?

Phillip J. Eby [email protected]
Tue, 21 Aug 2001 08:33:20 -0500


At 12:10 PM 8/21/01 +1000, Itai Tavor wrote:
>I got the following DataSkin class (Zope 2.3.2, ZPatterns 0.4.3p1):
>
>class MyClass(DataSkin):
>
>      def class_default_for_method1(self, REQUEST):
>         """ Display something """
>         ...
>
>Calling http://mysite/myinstance/method1 returns:
>
>Error Type: TypeError
>Error Value: unbound Python method must be called with MyClass 1st argument
>
>Why is method1 unbound? Why does it behave any different than a method 
>defined as def method1(self, REQUEST)? And what do I do to make this 
>method work?

Congratulations, you just found a long-buried bug in DynPersist.c, that 
hasn't hit anybody else yet (including me).  I just looked over the code 
and realized that DynPersist only calls the "__of__" method of an object 
returned from __get_attr__, and does not perform instance method 
binding.  This works correctly with methods that are Zope objects, just not 
methods that are Python functions or unbound methods.  There is a 
workaround, but of course I really should fix DynPersist.c, and will 
attempt to do so.  Here's the (untested) workaround:

import MethodObject

class Method(MethodObject.Method):

     def __init__(self,func):
         self.func = func
         self.func_code = func.func_code
         self.func_defaults = func.func_defaults

     def __call__(self,*args,**kw):
         return apply(self.func,args,kw)



class MyClass(DataSkin):

     def class_default_for_method1(self, REQUEST):
         ...

     class_default_for_method1 = Method(class_default_for_method1)


This should turn the Python function into a Zope "method" object with the 
right magic.  Sorry about the difficulty, I'll take a look and see if 
there's a way to fix DynPersist.c to do the right thing with "unbound 
method" objects.