Commit dece653b authored by Jim Fulton's avatar Jim Fulton

Fixed bug: External methods pickled function code and globals, which

was really stupid. It caused problems because func_defaults might
be non-unpicklable (e.g. includes somemodule.rfind).

Added simple unit test to allow me to fix the bug.
parent e1ed7d14
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
This product provides support for external methods, which allow This product provides support for external methods, which allow
domain-specific customization of web environments. domain-specific customization of web environments.
""" """
__version__='$Revision: 1.46 $'[11:-2] __version__='$Revision: 1.47 $'[11:-2]
from Globals import Persistent, DTMLFile, MessageDialog, HTML from Globals import Persistent, DTMLFile, MessageDialog, HTML
import OFS.SimpleItem, Acquisition import OFS.SimpleItem, Acquisition
import AccessControl.Role, sys, os, stat, traceback import AccessControl.Role, sys, os, stat, traceback
...@@ -77,9 +77,9 @@ class ExternalMethod(OFS.SimpleItem.Item, Persistent, Acquisition.Explicit, ...@@ -77,9 +77,9 @@ class ExternalMethod(OFS.SimpleItem.Item, Persistent, Acquisition.Explicit,
""" """
meta_type='External Method' meta_type = 'External Method'
func_defaults=() _v_func_defaults = ()
func_code=None _v_func_code = None
ZopeTime=Acquisition.Acquired ZopeTime=Acquisition.Acquired
HelpSys=Acquisition.Acquired HelpSys=Acquisition.Acquired
...@@ -136,17 +136,10 @@ class ExternalMethod(OFS.SimpleItem.Item, Persistent, Acquisition.Explicit, ...@@ -136,17 +136,10 @@ class ExternalMethod(OFS.SimpleItem.Item, Persistent, Acquisition.Explicit,
f=getObject(self._module, self._function, reload) f=getObject(self._module, self._function, reload)
if hasattr(f,'im_func'): ff=f.im_func if hasattr(f,'im_func'): ff=f.im_func
else: ff=f else: ff=f
if check:
# Check to make sure function signature is the same.
# Otherwise, we may end up causing an unwanted change.
if self.func_defaults != ff.func_defaults: self._v_func_defaults = ff.func_defaults
self.func_defaults = ff.func_defaults self._v_func_code = FuncCode(ff,f is not ff)
func_code=FuncCode(ff,f is not ff)
if func_code != self.func_code: self.func_code=func_code
self._v_f=f self._v_f=f
return f return f
...@@ -196,15 +189,15 @@ class ExternalMethod(OFS.SimpleItem.Item, Persistent, Acquisition.Explicit, ...@@ -196,15 +189,15 @@ class ExternalMethod(OFS.SimpleItem.Item, Persistent, Acquisition.Explicit,
f=self._v_f f=self._v_f
else: f=self.getFunction() else: f=self.getFunction()
__traceback_info__=args, kw, self.func_defaults __traceback_info__=args, kw, self._v_func_defaults
try: return apply(f,args,kw) try: return apply(f,args,kw)
except TypeError, v: except TypeError, v:
tb=sys.exc_info()[2] tb=sys.exc_info()[2]
try: try:
if ((self.func_code.co_argcount- if ((self._v_func_code.co_argcount-
len(self.func_defaults or ()) - 1 == len(args)) len(self._v_func_defaults or ()) - 1 == len(args))
and self.func_code.co_varnames[0]=='self'): and self._v_func_code.co_varnames[0]=='self'):
return apply(f,(self.aq_parent.this(),)+args,kw) return apply(f,(self.aq_parent.this(),)+args,kw)
raise TypeError, v, tb raise TypeError, v, tb
......
from math import sqrt
def testf(arg1, sqrt = sqrt):
return sqrt(arg1)
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""
$Id: __init__.py,v 1.2 2002/04/22 21:54:48 jim Exp $
"""
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""
Revision information:
$Id: testExternalMethod.py,v 1.2 2002/04/22 21:54:48 jim Exp $
"""
import math, os
from unittest import TestCase, TestSuite, main, makeSuite
import ZODB # dead goat
import Products.ExternalMethod.tests
from Products.ExternalMethod.ExternalMethod import ExternalMethod
class Test(TestCase):
def setUp(self):
self._old = __builtins__.__dict__.get('INSTANCE_HOME')
__builtins__.INSTANCE_HOME = os.path.split(
Products.ExternalMethod.tests.__file__)[0]
def tearDown(self):
if self._old is None:
del __builtins__.INSTANCE_HOME
else:
__builtins__.INSTANCE_HOME = self._old
def testStorage(self):
em1 = ExternalMethod('em', 'test method', 'Test', 'testf')
self.assertEqual(em1(4), math.sqrt(4))
state = em1.__getstate__()
em2 = ExternalMethod.__basicnew__()
em2.__setstate__(state)
self.assertEqual(em2(9), math.sqrt(9))
self.failIf(state.has_key('func_defaults'))
def test_suite():
return TestSuite((
makeSuite(Test),
))
def package_home(globals_dict):
__name__=globals_dict['__name__']
m=sys.modules[__name__]
if hasattr(m,'__path__'):
r=m.__path__[0]
elif "." in __name__:
r=sys.modules[__name__[:rfind(__name__,'.')]].__path__[0]
else:
r=__name__
return os.path.join(os.getcwd(), r)
if __name__=='__main__':
main(defaultTest='test_suite')
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment