parent: add descriptive errors for unsupported call() types.

Closes #439.
issue510
David Wilson 6 years ago
parent 94512f4ef8
commit 3876590aa1

@ -72,6 +72,10 @@ itervalues = getattr(dict, 'itervalues', dict.values)
if mitogen.core.PY3:
xrange = range
closure_attr = '__closure__'
else:
closure_attr = 'func_closure'
try:
SC_OPEN_MAX = os.sysconf('SC_OPEN_MAX')
@ -1344,8 +1348,31 @@ class CallChain(object):
finally:
self.chain_id = saved
closures_msg = (
'Mitogen cannot invoke closures, as doing so would require '
'serializing arbitrary program state, and no universal '
'method exists to recover a reference to them.'
)
lambda_msg = (
'Mitogen cannot invoke anonymous functions, as no universal method '
'exists to recover a reference to an anonymous function.'
)
method_msg = (
'Mitogen cannot invoke instance methods, as doing so would require '
'serializing arbitrary program state.'
)
def make_msg(self, fn, *args, **kwargs):
if inspect.ismethod(fn) and inspect.isclass(fn.__self__):
if getattr(fn, closure_attr, None) is not None:
raise TypeError(self.closures_msg)
if fn.__name__ == '<lambda>':
raise TypeError(self.lambda_msg)
if inspect.ismethod(fn):
if not inspect.isclass(fn.__self__):
raise TypeError(self.method_msg)
klass = mitogen.core.to_text(fn.__self__.__name__)
else:
klass = None

@ -155,5 +155,34 @@ class CallChainTest(testlib.RouterMixin, testlib.TestCase):
self.assertEquals('x3', c1.call(func_returns_arg, 'x3'))
class UnsupportedCallablesTest(testlib.RouterMixin, testlib.TestCase):
# Verify mitogen_chain functionality.
klass = mitogen.parent.CallChain
def setUp(self):
super(UnsupportedCallablesTest, self).setUp()
self.local = self.router.fork()
def test_closures_unsuppored(self):
a = 1
closure = lambda: a
e = self.assertRaises(TypeError,
lambda: self.local.call(closure))
self.assertEquals(e.args[0], self.klass.closures_msg)
def test_lambda_unsupported(self):
lam = lambda: None
e = self.assertRaises(TypeError,
lambda: self.local.call(lam))
self.assertEquals(e.args[0], self.klass.lambda_msg)
def test_instance_method_unsupported(self):
class X:
def x(): pass
e = self.assertRaises(TypeError,
lambda: self.local.call(X().x))
self.assertEquals(e.args[0], self.klass.method_msg)
if __name__ == '__main__':
unittest2.main()

Loading…
Cancel
Save