summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/xmlrpc.server.rst69
-rw-r--r--Doc/whatsnew/3.7.rst7
-rw-r--r--Lib/test/test_xmlrpc.py13
-rw-r--r--Lib/xmlrpc/server.py8
-rw-r--r--Misc/NEWS3
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.
diff --git a/Misc/NEWS b/Misc/NEWS
index a551127..4f19e75 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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