bpo-7769: enable xmlrpc.server.SimpleXMLRPCDispatcher.register_function used as decorator (GH-231)

This commit is contained in:
Xiang Zhang 2017-02-28 17:12:52 +08:00 committed by GitHub
parent 7c8b3fa31c
commit 267b9d2fa8
5 changed files with 80 additions and 20 deletions

View file

@ -79,13 +79,19 @@ The :class:`SimpleXMLRPCServer` class is based on
alone XML-RPC servers. 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, Register a function that can respond to XML-RPC requests. If *name* is given,
it will be the method name associated with *function*, otherwise it will be the method name associated with *function*, otherwise
``function.__name__`` will be used. *name* can be either a normal or Unicode ``function.__name__`` will be used. *name* is a string, and may contain
string, and may contain characters not legal in Python identifiers, including characters not legal in Python identifiers, including the period character.
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) .. method:: SimpleXMLRPCServer.register_instance(instance, allow_dotted_names=False)
@ -148,7 +154,7 @@ Server code::
rpc_paths = ('/RPC2',) rpc_paths = ('/RPC2',)
# Create server # Create server
with SimpleXMLRPCServer(("localhost", 8000), with SimpleXMLRPCServer(('localhost', 8000),
requestHandler=RequestHandler) as server: requestHandler=RequestHandler) as server:
server.register_introspection_functions() server.register_introspection_functions()
@ -157,7 +163,7 @@ Server code::
server.register_function(pow) server.register_function(pow)
# Register a function under a different name # Register a function under a different name
def adder_function(x,y): def adder_function(x, y):
return x + y return x + y
server.register_function(adder_function, 'add') server.register_function(adder_function, 'add')
@ -185,6 +191,37 @@ server::
# Print list of available methods # Print list of available methods
print(s.system.listMethods()) 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 The following example included in the :file:`Lib/xmlrpc/server.py` module shows
a server allowing dotted names and registering a multicall function. 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 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. 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, Register a function that can respond to XML-RPC requests. If *name* is given,
it will be the method name associated with function, otherwise it will be the method name associated with *function*, otherwise
*function.__name__* will be used. *name* can be either a normal or Unicode ``function.__name__`` will be used. *name* is a string, and may contain
string, and may contain characters not legal in Python identifiers, including characters not legal in Python identifiers, including the period character.
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:: CGIXMLRPCRequestHandler.register_instance(instance) .. method:: CGIXMLRPCRequestHandler.register_instance(instance)

View file

@ -104,6 +104,13 @@ The :const:`~unittest.mock.sentinel` attributes now preserve their identity
when they are :mod:`copied <copy>` or :mod:`pickled <pickle>`. when they are :mod:`copied <copy>` or :mod:`pickled <pickle>`.
(Contributed by Serhiy Storchaka in :issue:`20804`.) (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 urllib.parse
------------ ------------

View file

@ -505,10 +505,6 @@ def http_server(evt, numrequests, requestHandler=None, encoding=None):
def getData(): def getData():
return '42' return '42'
def my_function():
'''This is my function'''
return True
class MyXMLRPCServer(xmlrpc.server.SimpleXMLRPCServer): class MyXMLRPCServer(xmlrpc.server.SimpleXMLRPCServer):
def get_request(self): def get_request(self):
# Ensure the socket is always non-blocking. On Linux, socket # 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_introspection_functions()
serv.register_multicall_functions() serv.register_multicall_functions()
serv.register_function(pow) serv.register_function(pow)
serv.register_function(lambda x,y: x+y, 'add')
serv.register_function(lambda x: x, 'têšt') 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() testInstance = TestInstanceClass()
serv.register_instance(testInstance, allow_dotted_names=True) serv.register_instance(testInstance, allow_dotted_names=True)
evt.set() evt.set()

View file

@ -106,6 +106,7 @@ server.handle_request()
from xmlrpc.client import Fault, dumps, loads, gzip_encode, gzip_decode from xmlrpc.client import Fault, dumps, loads, gzip_encode, gzip_decode
from http.server import BaseHTTPRequestHandler from http.server import BaseHTTPRequestHandler
from functools import partial
import http.server import http.server
import socketserver import socketserver
import sys import sys
@ -204,17 +205,22 @@ class SimpleXMLRPCDispatcher:
self.instance = instance self.instance = instance
self.allow_dotted_names = allow_dotted_names 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. """Registers a function to respond to XML-RPC requests.
The optional name argument can be used to set a Unicode name The optional name argument can be used to set a Unicode name
for the function. for the function.
""" """
# decorator factory
if function is None:
return partial(self.register_function, name=name)
if name is None: if name is None:
name = function.__name__ name = function.__name__
self.funcs[name] = function self.funcs[name] = function
return function
def register_introspection_functions(self): def register_introspection_functions(self):
"""Registers the XML-RPC introspection methods in the system """Registers the XML-RPC introspection methods in the system
namespace. namespace.

View file

@ -249,6 +249,9 @@ Extension Modules
Library 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-29376: Fix assertion error in threading._DummyThread.is_alive().
- bpo-28624: Add a test that checks that cwd parameter of Popen() accepts - bpo-28624: Add a test that checks that cwd parameter of Popen() accepts