Skip to content

Commit 3405792

Browse files
petr-motejlekserhiy-storchaka
authored andcommitted
bpo-29615: backport to 3.6 (#478)
1 parent 8192402 commit 3405792

File tree

3 files changed

+117
-20
lines changed

3 files changed

+117
-20
lines changed

Diff for: Lib/test/test_xmlrpc.py

+89-1
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,94 @@ def run_server():
343343
self.assertEqual(p.method(), 5)
344344
self.assertEqual(p.method(), 5)
345345

346+
347+
class SimpleXMLRPCDispatcherTestCase(unittest.TestCase):
348+
class DispatchExc(Exception):
349+
"""Raised inside the dispatched functions when checking for
350+
chained exceptions"""
351+
352+
def test_call_registered_func(self):
353+
"""Calls explicitly registered function"""
354+
# Makes sure any exception raised inside the function has no other
355+
# exception chained to it
356+
357+
exp_params = 1, 2, 3
358+
359+
def dispatched_func(*params):
360+
raise self.DispatchExc(params)
361+
362+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
363+
dispatcher.register_function(dispatched_func)
364+
with self.assertRaises(self.DispatchExc) as exc_ctx:
365+
dispatcher._dispatch('dispatched_func', exp_params)
366+
self.assertEqual(exc_ctx.exception.args, (exp_params,))
367+
self.assertIsNone(exc_ctx.exception.__cause__)
368+
self.assertIsNone(exc_ctx.exception.__context__)
369+
370+
def test_call_instance_func(self):
371+
"""Calls a registered instance attribute as a function"""
372+
# Makes sure any exception raised inside the function has no other
373+
# exception chained to it
374+
375+
exp_params = 1, 2, 3
376+
377+
class DispatchedClass:
378+
def dispatched_func(self, *params):
379+
raise SimpleXMLRPCDispatcherTestCase.DispatchExc(params)
380+
381+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
382+
dispatcher.register_instance(DispatchedClass())
383+
with self.assertRaises(self.DispatchExc) as exc_ctx:
384+
dispatcher._dispatch('dispatched_func', exp_params)
385+
self.assertEqual(exc_ctx.exception.args, (exp_params,))
386+
self.assertIsNone(exc_ctx.exception.__cause__)
387+
self.assertIsNone(exc_ctx.exception.__context__)
388+
389+
def test_call_dispatch_func(self):
390+
"""Calls the registered instance's `_dispatch` function"""
391+
# Makes sure any exception raised inside the function has no other
392+
# exception chained to it
393+
394+
exp_method = 'method'
395+
exp_params = 1, 2, 3
396+
397+
class TestInstance:
398+
def _dispatch(self, method, params):
399+
raise SimpleXMLRPCDispatcherTestCase.DispatchExc(
400+
method, params)
401+
402+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
403+
dispatcher.register_instance(TestInstance())
404+
with self.assertRaises(self.DispatchExc) as exc_ctx:
405+
dispatcher._dispatch(exp_method, exp_params)
406+
self.assertEqual(exc_ctx.exception.args, (exp_method, exp_params))
407+
self.assertIsNone(exc_ctx.exception.__cause__)
408+
self.assertIsNone(exc_ctx.exception.__context__)
409+
410+
def test_registered_func_is_none(self):
411+
"""Calls explicitly registered function which is None"""
412+
413+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
414+
dispatcher.register_function(None, name='method')
415+
with self.assertRaises(Exception, expected_regex='method'):
416+
dispatcher._dispatch('method', ('param',))
417+
418+
def test_instance_has_no_func(self):
419+
"""Attempts to call nonexistent function on a registered instance"""
420+
421+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
422+
dispatcher.register_instance(object())
423+
with self.assertRaises(Exception, expected_regex='method'):
424+
dispatcher._dispatch('method', ('param',))
425+
426+
def test_cannot_locate_func(self):
427+
"""Calls a function that the dispatcher cannot locate"""
428+
429+
dispatcher = xmlrpc.server.SimpleXMLRPCDispatcher()
430+
with self.assertRaises(Exception, expected_regex='method'):
431+
dispatcher._dispatch('method', ('param',))
432+
433+
346434
class HelperTestCase(unittest.TestCase):
347435
def test_escape(self):
348436
self.assertEqual(xmlrpclib.escape("a&b"), "a&b")
@@ -1312,7 +1400,7 @@ def test_main():
13121400
KeepaliveServerTestCase1, KeepaliveServerTestCase2,
13131401
GzipServerTestCase, GzipUtilTestCase,
13141402
MultiPathServerTestCase, ServerProxyTestCase, FailingServerTestCase,
1315-
CGIHandlerTestCase)
1403+
CGIHandlerTestCase, SimpleXMLRPCDispatcherTestCase)
13161404

13171405

13181406
if __name__ == "__main__":

Diff for: Lib/xmlrpc/server.py

+24-19
Original file line numberDiff line numberDiff line change
@@ -386,31 +386,36 @@ def _dispatch(self, method, params):
386386
not be called.
387387
"""
388388

389-
func = None
390389
try:
391-
# check to see if a matching function has been registered
390+
# call the matching registered function
392391
func = self.funcs[method]
393392
except KeyError:
394-
if self.instance is not None:
395-
# check for a _dispatch method
396-
if hasattr(self.instance, '_dispatch'):
397-
return self.instance._dispatch(method, params)
398-
else:
399-
# call instance method directly
400-
try:
401-
func = resolve_dotted_attribute(
402-
self.instance,
403-
method,
404-
self.allow_dotted_names
405-
)
406-
except AttributeError:
407-
pass
408-
409-
if func is not None:
410-
return func(*params)
393+
pass
411394
else:
395+
if func is not None:
396+
return func(*params)
412397
raise Exception('method "%s" is not supported' % method)
413398

399+
if self.instance is not None:
400+
if hasattr(self.instance, '_dispatch'):
401+
# call the `_dispatch` method on the instance
402+
return self.instance._dispatch(method, params)
403+
404+
# call the instance's method directly
405+
try:
406+
func = resolve_dotted_attribute(
407+
self.instance,
408+
method,
409+
self.allow_dotted_names
410+
)
411+
except AttributeError:
412+
pass
413+
else:
414+
if func is not None:
415+
return func(*params)
416+
417+
raise Exception('method "%s" is not supported' % method)
418+
414419
class SimpleXMLRPCRequestHandler(BaseHTTPRequestHandler):
415420
"""Simple XML-RPC request handler class.
416421

Diff for: Misc/NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ Core and Builtins
1313
Library
1414
-------
1515

16+
- bpo-29615: SimpleXMLRPCDispatcher no longer chains KeyError (or any other
17+
exception) to exception(s) raised in the dispatched methods.
18+
Patch by Petr Motejlek.
19+
1620

1721
What's New in Python 3.6.1 release candidate 1
1822
==============================================

0 commit comments

Comments
 (0)