diff options
-rw-r--r-- | Doc/library/xmlrpc.server.rst | 69 | ||||
-rw-r--r-- | Doc/whatsnew/3.7.rst | 7 | ||||
-rw-r--r-- | Lib/test/test_xmlrpc.py | 13 | ||||
-rw-r--r-- | Lib/xmlrpc/server.py | 8 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
5 files changed, 80 insertions, 20 deletions
diff --git a/Doc/library/xmlrpc.server.rst b/Doc/library/xmlrpc.server.rst index 0511ddf..7d561e2 100644 --- a/Doc/library/xmlrpc.server.rst +++ b/Doc/library/xmlrpc.server.rst @@ -79,13 +79,19 @@ The :class:`SimpleXMLRPCServer` class is based on alone XML-RPC servers. -.. method:: SimpleXMLRPCServer.register_function(function, name=None) +.. method:: SimpleXMLRPCServer.register_function(function=None, name=None) Register a function that can respond to XML-RPC requests. If *name* is given, it will be the method name associated with *function*, otherwise - ``function.__name__`` will be used. *name* can be either a normal or Unicode - string, and may contain characters not legal in Python identifiers, including - the period character. + ``function.__name__`` will be used. *name* is a string, and may contain + characters not legal in Python identifiers, including the period character. + + This method can also be used as a decorator. When used as a decorator, + *name* can only be given as a keyword argument to register *function* under + *name*. If no *name* is given, ``function.__name__`` will be used. + + .. versionchanged:: 3.7 + :meth:`register_function` can be used as a decorator. .. method:: SimpleXMLRPCServer.register_instance(instance, allow_dotted_names=False) @@ -148,7 +154,7 @@ Server code:: rpc_paths = ('/RPC2',) # Create server - with SimpleXMLRPCServer(("localhost", 8000), + with SimpleXMLRPCServer(('localhost', 8000), requestHandler=RequestHandler) as server: server.register_introspection_functions() @@ -157,7 +163,7 @@ Server code:: server.register_function(pow) # Register a function under a different name - def adder_function(x,y): + def adder_function(x, y): return x + y server.register_function(adder_function, 'add') @@ -185,6 +191,37 @@ server:: # Print list of available methods print(s.system.listMethods()) +:meth:`register_function` can also be used as a decorator. The previous server +example can register functions in a decorator way:: + + from xmlrpc.server import SimpleXMLRPCServer + from xmlrpc.server import SimpleXMLRPCRequestHandler + + class RequestHandler(SimpleXMLRPCRequestHandler): + rpc_paths = ('/RPC2',) + + with SimpleXMLRPCServer(('localhost', 8000), + requestHandler=RequestHandler) as server: + server.register_introspection_functions() + + # Register pow() function; this will use the value of + # pow.__name__ as the name, which is just 'pow'. + server.register_function(pow) + + # Register a function under a different name, using + # register_function as a decorator. *name* can only be given + # as a keyword argument. + @server.register_function(name='add') + def adder_function(x, y): + return x + y + + # Register a function under function.__name__. + @server.register_function + def mul(x, y): + return x * y + + server.serve_forever() + The following example included in the :file:`Lib/xmlrpc/server.py` module shows a server allowing dotted names and registering a multicall function. @@ -252,17 +289,23 @@ This client which interacts with the demo XMLRPC server can be invoked as:: CGIXMLRPCRequestHandler ----------------------- -The :class:`CGIXMLRPCRequestHandler` class can be used to handle XML-RPC +The :class:`CGIXMLRPCRequestHandler` class can be used to handle XML-RPC requests sent to Python CGI scripts. -.. method:: CGIXMLRPCRequestHandler.register_function(function, name=None) +.. method:: CGIXMLRPCRequestHandler.register_function(function=None, name=None) + + Register a function that can respond to XML-RPC requests. If *name* is given, + it will be the method name associated with *function*, otherwise + ``function.__name__`` will be used. *name* is a string, and may contain + characters not legal in Python identifiers, including the period character. + + This method can also be used as a decorator. When used as a decorator, + *name* can only be given as a keyword argument to register *function* under + *name*. If no *name* is given, ``function.__name__`` will be used. - Register a function that can respond to XML-RPC requests. If *name* is given, - it will be the method name associated with function, otherwise - *function.__name__* will be used. *name* can be either a normal or Unicode - string, and may contain characters not legal in Python identifiers, including - the period character. + .. versionchanged:: 3.7 + :meth:`register_function` can be used as a decorator. .. method:: CGIXMLRPCRequestHandler.register_instance(instance) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 6c071ad..1f5aa79 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -104,6 +104,13 @@ The :const:`~unittest.mock.sentinel` attributes now preserve their identity when they are :mod:`copied <copy>` or :mod:`pickled <pickle>`. (Contributed by Serhiy Storchaka in :issue:`20804`.) +xmlrpc.server +------------- + +:meth:`register_function` of :class:`xmlrpc.server.SimpleXMLRPCDispatcher` and +its subclasses can be used as a decorator. +(Contributed by Xiang Zhang in :issue:`7769`.) + urllib.parse ------------ diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index df9c79e..ef8ad21 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -505,10 +505,6 @@ def http_server(evt, numrequests, requestHandler=None, encoding=None): def getData(): return '42' - def my_function(): - '''This is my function''' - return True - class MyXMLRPCServer(xmlrpc.server.SimpleXMLRPCServer): def get_request(self): # Ensure the socket is always non-blocking. On Linux, socket @@ -535,9 +531,14 @@ def http_server(evt, numrequests, requestHandler=None, encoding=None): serv.register_introspection_functions() serv.register_multicall_functions() serv.register_function(pow) - serv.register_function(lambda x,y: x+y, 'add') serv.register_function(lambda x: x, 'têšt') - serv.register_function(my_function) + @serv.register_function + def my_function(): + '''This is my function''' + return True + @serv.register_function(name='add') + def _(x, y): + return x + y testInstance = TestInstanceClass() serv.register_instance(testInstance, allow_dotted_names=True) evt.set() diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py index 849bfdd..a6275a1 100644 --- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -106,6 +106,7 @@ server.handle_request() from xmlrpc.client import Fault, dumps, loads, gzip_encode, gzip_decode from http.server import BaseHTTPRequestHandler +from functools import partial import http.server import socketserver import sys @@ -204,17 +205,22 @@ class SimpleXMLRPCDispatcher: self.instance = instance self.allow_dotted_names = allow_dotted_names - def register_function(self, function, name=None): + def register_function(self, function=None, name=None): """Registers a function to respond to XML-RPC requests. The optional name argument can be used to set a Unicode name for the function. """ + # decorator factory + if function is None: + return partial(self.register_function, name=name) if name is None: name = function.__name__ self.funcs[name] = function + return function + def register_introspection_functions(self): """Registers the XML-RPC introspection methods in the system namespace. @@ -249,6 +249,9 @@ Extension Modules Library ------- +- bpo-7769: Method register_function() of xmlrpc.server.SimpleXMLRPCDispatcher + and its subclasses can now be used as a decorator. + - bpo-29376: Fix assertion error in threading._DummyThread.is_alive(). - bpo-28624: Add a test that checks that cwd parameter of Popen() accepts |