bpo-29615: SimpleXMLRPCDispatcher no longer chains KeyError (#260)
(or any other exception) to exception(s) raised in the dispatched methods. Patch by Petr Motejlek.
This commit is contained in:
parent
da62373b0d
commit
3c6314c08d
|
@ -343,6 +343,94 @@ class XMLRPCTestCase(unittest.TestCase):
|
||||||
self.assertEqual(p.method(), 5)
|
self.assertEqual(p.method(), 5)
|
||||||
self.assertEqual(p.method(), 5)
|
self.assertEqual(p.method(), 5)
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleXMLRPCDispatcherTestCase(unittest.TestCase):
|
||||||
|
class DispatchExc(Exception):
|
||||||
|
"""Raised inside the dispatched functions when checking for
|
||||||
|
chained exceptions"""
|
||||||
|
|
||||||
|
def test_call_registered_func(self):
|
||||||
|
"""Calls explicitly registered function"""
|
||||||
|
# Makes sure any exception raised inside the function has no other
|
||||||
|
# exception chained to it
|
||||||
|
|
||||||
|
exp_params = 1, 2, 3
|
||||||
|
|
||||||
|
def dispatched_func(*params):
|
||||||
|
raise self.DispatchExc(params)
|
||||||
|
|
||||||
|
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
|
||||||
|
dispatcher.register_function(dispatched_func)
|
||||||
|
with self.assertRaises(self.DispatchExc) as exc_ctx:
|
||||||
|
dispatcher._dispatch('dispatched_func', exp_params)
|
||||||
|
self.assertEqual(exc_ctx.exception.args, (exp_params,))
|
||||||
|
self.assertIsNone(exc_ctx.exception.__cause__)
|
||||||
|
self.assertIsNone(exc_ctx.exception.__context__)
|
||||||
|
|
||||||
|
def test_call_instance_func(self):
|
||||||
|
"""Calls a registered instance attribute as a function"""
|
||||||
|
# Makes sure any exception raised inside the function has no other
|
||||||
|
# exception chained to it
|
||||||
|
|
||||||
|
exp_params = 1, 2, 3
|
||||||
|
|
||||||
|
class DispatchedClass:
|
||||||
|
def dispatched_func(self, *params):
|
||||||
|
raise SimpleXMLRPCDispatcherTestCase.DispatchExc(params)
|
||||||
|
|
||||||
|
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
|
||||||
|
dispatcher.register_instance(DispatchedClass())
|
||||||
|
with self.assertRaises(self.DispatchExc) as exc_ctx:
|
||||||
|
dispatcher._dispatch('dispatched_func', exp_params)
|
||||||
|
self.assertEqual(exc_ctx.exception.args, (exp_params,))
|
||||||
|
self.assertIsNone(exc_ctx.exception.__cause__)
|
||||||
|
self.assertIsNone(exc_ctx.exception.__context__)
|
||||||
|
|
||||||
|
def test_call_dispatch_func(self):
|
||||||
|
"""Calls the registered instance's `_dispatch` function"""
|
||||||
|
# Makes sure any exception raised inside the function has no other
|
||||||
|
# exception chained to it
|
||||||
|
|
||||||
|
exp_method = 'method'
|
||||||
|
exp_params = 1, 2, 3
|
||||||
|
|
||||||
|
class TestInstance:
|
||||||
|
def _dispatch(self, method, params):
|
||||||
|
raise SimpleXMLRPCDispatcherTestCase.DispatchExc(
|
||||||
|
method, params)
|
||||||
|
|
||||||
|
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
|
||||||
|
dispatcher.register_instance(TestInstance())
|
||||||
|
with self.assertRaises(self.DispatchExc) as exc_ctx:
|
||||||
|
dispatcher._dispatch(exp_method, exp_params)
|
||||||
|
self.assertEqual(exc_ctx.exception.args, (exp_method, exp_params))
|
||||||
|
self.assertIsNone(exc_ctx.exception.__cause__)
|
||||||
|
self.assertIsNone(exc_ctx.exception.__context__)
|
||||||
|
|
||||||
|
def test_registered_func_is_none(self):
|
||||||
|
"""Calls explicitly registered function which is None"""
|
||||||
|
|
||||||
|
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
|
||||||
|
dispatcher.register_function(None, name='method')
|
||||||
|
with self.assertRaises(Exception, expected_regex='method'):
|
||||||
|
dispatcher._dispatch('method', ('param',))
|
||||||
|
|
||||||
|
def test_instance_has_no_func(self):
|
||||||
|
"""Attempts to call nonexistent function on a registered instance"""
|
||||||
|
|
||||||
|
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
|
||||||
|
dispatcher.register_instance(object())
|
||||||
|
with self.assertRaises(Exception, expected_regex='method'):
|
||||||
|
dispatcher._dispatch('method', ('param',))
|
||||||
|
|
||||||
|
def test_cannot_locate_func(self):
|
||||||
|
"""Calls a function that the dispatcher cannot locate"""
|
||||||
|
|
||||||
|
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
|
||||||
|
with self.assertRaises(Exception, expected_regex='method'):
|
||||||
|
dispatcher._dispatch('method', ('param',))
|
||||||
|
|
||||||
|
|
||||||
class HelperTestCase(unittest.TestCase):
|
class HelperTestCase(unittest.TestCase):
|
||||||
def test_escape(self):
|
def test_escape(self):
|
||||||
self.assertEqual(xmlrpclib.escape("a&b"), "a&b")
|
self.assertEqual(xmlrpclib.escape("a&b"), "a&b")
|
||||||
|
@ -1313,7 +1401,7 @@ def test_main():
|
||||||
KeepaliveServerTestCase1, KeepaliveServerTestCase2,
|
KeepaliveServerTestCase1, KeepaliveServerTestCase2,
|
||||||
GzipServerTestCase, GzipUtilTestCase,
|
GzipServerTestCase, GzipUtilTestCase,
|
||||||
MultiPathServerTestCase, ServerProxyTestCase, FailingServerTestCase,
|
MultiPathServerTestCase, ServerProxyTestCase, FailingServerTestCase,
|
||||||
CGIHandlerTestCase)
|
CGIHandlerTestCase, SimpleXMLRPCDispatcherTestCase)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -392,31 +392,36 @@ class SimpleXMLRPCDispatcher:
|
||||||
not be called.
|
not be called.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
func = None
|
|
||||||
try:
|
try:
|
||||||
# check to see if a matching function has been registered
|
# call the matching registered function
|
||||||
func = self.funcs[method]
|
func = self.funcs[method]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if self.instance is not None:
|
pass
|
||||||
# check for a _dispatch method
|
|
||||||
if hasattr(self.instance, '_dispatch'):
|
|
||||||
return self.instance._dispatch(method, params)
|
|
||||||
else:
|
|
||||||
# call instance method directly
|
|
||||||
try:
|
|
||||||
func = resolve_dotted_attribute(
|
|
||||||
self.instance,
|
|
||||||
method,
|
|
||||||
self.allow_dotted_names
|
|
||||||
)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if func is not None:
|
|
||||||
return func(*params)
|
|
||||||
else:
|
else:
|
||||||
|
if func is not None:
|
||||||
|
return func(*params)
|
||||||
raise Exception('method "%s" is not supported' % method)
|
raise Exception('method "%s" is not supported' % method)
|
||||||
|
|
||||||
|
if self.instance is not None:
|
||||||
|
if hasattr(self.instance, '_dispatch'):
|
||||||
|
# call the `_dispatch` method on the instance
|
||||||
|
return self.instance._dispatch(method, params)
|
||||||
|
|
||||||
|
# call the instance's method directly
|
||||||
|
try:
|
||||||
|
func = resolve_dotted_attribute(
|
||||||
|
self.instance,
|
||||||
|
method,
|
||||||
|
self.allow_dotted_names
|
||||||
|
)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if func is not None:
|
||||||
|
return func(*params)
|
||||||
|
|
||||||
|
raise Exception('method "%s" is not supported' % method)
|
||||||
|
|
||||||
class SimpleXMLRPCRequestHandler(BaseHTTPRequestHandler):
|
class SimpleXMLRPCRequestHandler(BaseHTTPRequestHandler):
|
||||||
"""Simple XML-RPC request handler class.
|
"""Simple XML-RPC request handler class.
|
||||||
|
|
||||||
|
|
|
@ -253,6 +253,10 @@ Extension Modules
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- bpo-29615: SimpleXMLRPCDispatcher no longer chains KeyError (or any other
|
||||||
|
exception) to exception(s) raised in the dispatched methods.
|
||||||
|
Patch by Petr Motejlek.
|
||||||
|
|
||||||
- bpo-7769: Method register_function() of xmlrpc.server.SimpleXMLRPCDispatcher
|
- bpo-7769: Method register_function() of xmlrpc.server.SimpleXMLRPCDispatcher
|
||||||
and its subclasses can now be used as a decorator.
|
and its subclasses can now be used as a decorator.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue