From 87fef8d05d1d24b995daa41b980e95e879d54763 Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Wed, 22 Feb 2017 13:30:25 +0800 Subject: [PATCH 1/9] make SimpleXMLRPCServer.SimpleXMLRPCServer.register_function as decorator --- Doc/library/xmlrpc.server.rst | 61 +++++++++++++++++++++++++++++++---- Lib/test/test_xmlrpc.py | 13 ++++---- Lib/xmlrpc/server.py | 8 ++++- 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/Doc/library/xmlrpc.server.rst b/Doc/library/xmlrpc.server.rst index 0511ddf47e9948..48ddc7473ec817 100644 --- a/Doc/library/xmlrpc.server.rst +++ b/Doc/library/xmlrpc.server.rst @@ -79,7 +79,7 @@ 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 @@ -87,6 +87,14 @@ alone XML-RPC servers. string, and may contain characters not legal in Python identifiers, including the period character. + From version 3.7, this method can also be used as a decorator. When used as + a decorator, *name* can be given as a keyword-only argument to register + *function* under *name*. If no *name* is given, ``function.__name__`` will be + used. + + .. versionadded:: 3.7 + :meth:`register_function` can be used as a decorator. + .. method:: SimpleXMLRPCServer.register_instance(instance, allow_dotted_names=False) @@ -185,6 +193,37 @@ server:: # Print list of available methods print(s.system.listMethods()) +Since version 3.7, :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,18 +291,26 @@ 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* can be either a normal or Unicode - string, and may contain characters not legal in Python identifiers, including + 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. + From version 3.7, this method can also be used as a decorator. When used as + a decorator, *name* can be given as a keyword-only argument to register + *function* under *name*. If no *name* is given, ``function.__name__`` will be + used. + + .. versionadded:: 3.7 + :meth:`register_function` can be used as a decorator. + .. method:: CGIXMLRPCRequestHandler.register_instance(instance) diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index df9c79e3df0689..ef8ad217eae61f 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -505,10 +505,6 @@ class Fixture: 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 get_request(self): 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 849bfddd84816f..a6275a1b746844 100644 --- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -106,6 +106,7 @@ def export_add(self, x, y): 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 @@ def register_instance(self, instance, allow_dotted_names=False): 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. From fde883e1c783105267cf82f73b2014a75daef96a Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Wed, 22 Feb 2017 13:52:19 +0800 Subject: [PATCH 2/9] add news entry --- Doc/whatsnew/3.7.rst | 8 ++++++++ Misc/NEWS | 3 +++ 2 files changed, 11 insertions(+) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 21621c5ee4eac9..72255a8347dfd3 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -100,6 +100,14 @@ The :const:`~unittest.mock.sentinel` attributes now preserve their identity when they are :mod:`copied ` or :mod:`pickled `. (Contributed by Serhiy Storchaka in :issue:`20804`.) +xmlrpc.server +------------- + +:meth:`xmlrpc.server.SimpleXMLRPCServer.register_function()` and +:meth:`xmlrpc.server.CGIXMLRPCRequestHandler.register_function()` can now be +used as a decorator. +(Contributed by Xiang Zhang in :issue:`7769`.) + Optimizations ============= diff --git a/Misc/NEWS b/Misc/NEWS index 4d1cf298ae5df9..d222336ae02bb2 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -239,6 +239,9 @@ Extension Modules Library ------- +- bpo-7769: Method register_function() of xmlrpc.server.SimpleXMLRPCServer + and xmlrpc.server.CGIXMLRPCRequestHandler can now be used as a decorator. + - bpo-29532: Altering a kwarg dictionary passed to functools.partial() no longer affects a partial object after creation. From c0c01b033cdca7f233c50b3faabb27e87db09310 Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Wed, 22 Feb 2017 14:04:09 +0800 Subject: [PATCH 3/9] alter NEWS --- Doc/whatsnew/3.7.rst | 5 ++--- Misc/NEWS | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 72255a8347dfd3..6ea1e55ade72c3 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -103,9 +103,8 @@ when they are :mod:`copied ` or :mod:`pickled `. xmlrpc.server ------------- -:meth:`xmlrpc.server.SimpleXMLRPCServer.register_function()` and -:meth:`xmlrpc.server.CGIXMLRPCRequestHandler.register_function()` can now be -used as a decorator. +:meth:`register_function` of :class:`xmlrpc.server.SimpleXMLRPCDispatcher` and +its subclasses can be used as a decorator. (Contributed by Xiang Zhang in :issue:`7769`.) diff --git a/Misc/NEWS b/Misc/NEWS index d222336ae02bb2..1e3e4782342ce8 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -239,8 +239,8 @@ Extension Modules Library ------- -- bpo-7769: Method register_function() of xmlrpc.server.SimpleXMLRPCServer - and xmlrpc.server.CGIXMLRPCRequestHandler can now be used as a decorator. +- bpo-7769: Method register_function() of xmlrpc.server.SimpleXMLRPCDispatcher + and its subclasses can now be used as a decorator. - bpo-29532: Altering a kwarg dictionary passed to functools.partial() no longer affects a partial object after creation. From d4104ebcad76179d779f8c09a33a800eda794204 Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Tue, 28 Feb 2017 14:35:30 +0800 Subject: [PATCH 4/9] change versionadded to versionchanged --- Doc/library/xmlrpc.server.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/xmlrpc.server.rst b/Doc/library/xmlrpc.server.rst index 48ddc7473ec817..61a8781923fea0 100644 --- a/Doc/library/xmlrpc.server.rst +++ b/Doc/library/xmlrpc.server.rst @@ -92,7 +92,7 @@ alone XML-RPC servers. *function* under *name*. If no *name* is given, ``function.__name__`` will be used. - .. versionadded:: 3.7 + .. versionchanged:: 3.7 :meth:`register_function` can be used as a decorator. @@ -308,7 +308,7 @@ requests sent to Python CGI scripts. *function* under *name*. If no *name* is given, ``function.__name__`` will be used. - .. versionadded:: 3.7 + .. versionchanged:: 3.7 :meth:`register_function` can be used as a decorator. From 51a3353e078578fac9479d8e3f9543b8043728b6 Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Tue, 28 Feb 2017 15:25:35 +0800 Subject: [PATCH 5/9] remove outdated doc --- Doc/library/xmlrpc.server.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Doc/library/xmlrpc.server.rst b/Doc/library/xmlrpc.server.rst index 61a8781923fea0..ab120cd59a02b9 100644 --- a/Doc/library/xmlrpc.server.rst +++ b/Doc/library/xmlrpc.server.rst @@ -83,9 +83,8 @@ alone XML-RPC servers. 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. From version 3.7, this method can also be used as a decorator. When used as a decorator, *name* can be given as a keyword-only argument to register @@ -299,9 +298,8 @@ requests sent to Python CGI scripts. 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. From version 3.7, this method can also be used as a decorator. When used as a decorator, *name* can be given as a keyword-only argument to register From a19d74ef923aba0761b4eb7c18b1fe158dc730de Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Tue, 28 Feb 2017 15:30:38 +0800 Subject: [PATCH 6/9] fix style --- Misc/NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/Misc/NEWS b/Misc/NEWS index 96627c438ecaf5..4f19e75aeaa8fc 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -251,6 +251,7 @@ 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 From eaa27d9d17aa0e2818e3b90e5ca6e3136165fc83 Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Tue, 28 Feb 2017 16:09:27 +0800 Subject: [PATCH 7/9] fix style nits --- Doc/library/xmlrpc.server.rst | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Doc/library/xmlrpc.server.rst b/Doc/library/xmlrpc.server.rst index ab120cd59a02b9..eb419d4fcc91ea 100644 --- a/Doc/library/xmlrpc.server.rst +++ b/Doc/library/xmlrpc.server.rst @@ -86,10 +86,9 @@ alone XML-RPC servers. ``function.__name__`` will be used. *name* is a string, and may contain characters not legal in Python identifiers, including the period character. - From version 3.7, this method can also be used as a decorator. When used as - a decorator, *name* can be given as a keyword-only argument to register - *function* under *name*. If no *name* is given, ``function.__name__`` will be - used. + This method can also be used as a decorator. When used as a decorator, + *name* can be given as a keyword-only 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. @@ -155,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() @@ -164,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') @@ -192,8 +191,8 @@ server:: # Print list of available methods print(s.system.listMethods()) -Since version 3.7, :meth:`register_function` can also be used as a decorator. The -previous server example can register functions in a decorator way:: +: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 @@ -201,7 +200,7 @@ previous server example can register functions in a decorator way:: class RequestHandler(SimpleXMLRPCRequestHandler): rpc_paths = ('/RPC2',) - with SimpleXMLRPCServer(("localhost", 8000), + with SimpleXMLRPCServer(('localhost', 8000), requestHandler=RequestHandler) as server: server.register_introspection_functions() @@ -213,7 +212,7 @@ previous server example can register functions in a decorator way:: # register_function as a decorator. *name* can only be given # as a keyword argument. @server.register_function(name='add') - def adder_function(x,y): + def adder_function(x, y): return x + y # Register a function under function.__name__. @@ -301,10 +300,9 @@ requests sent to Python CGI scripts. ``function.__name__`` will be used. *name* is a string, and may contain characters not legal in Python identifiers, including the period character. - From version 3.7, this method can also be used as a decorator. When used as - a decorator, *name* can be given as a keyword-only argument to register - *function* under *name*. If no *name* is given, ``function.__name__`` will be - used. + This method can also be used as a decorator. When used as a decorator, + *name* can be given as a keyword-only 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. From 8a3f4c3a9a7123e8577de785dfb956add5c68108 Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Tue, 28 Feb 2017 16:22:14 +0800 Subject: [PATCH 8/9] adjust phrase --- Doc/library/xmlrpc.server.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Doc/library/xmlrpc.server.rst b/Doc/library/xmlrpc.server.rst index eb419d4fcc91ea..d9060a7ec97214 100644 --- a/Doc/library/xmlrpc.server.rst +++ b/Doc/library/xmlrpc.server.rst @@ -209,8 +209,7 @@ example can register functions in a decorator way:: 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. + # register_function as a decorator. *name* is keyword-only. @server.register_function(name='add') def adder_function(x, y): return x + y From 391b140c0b9a3b0bcdd8abec2d1f705733e9c816 Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Tue, 28 Feb 2017 16:41:39 +0800 Subject: [PATCH 9/9] fix wording --- Doc/library/xmlrpc.server.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/library/xmlrpc.server.rst b/Doc/library/xmlrpc.server.rst index d9060a7ec97214..7d561e2303f898 100644 --- a/Doc/library/xmlrpc.server.rst +++ b/Doc/library/xmlrpc.server.rst @@ -87,7 +87,7 @@ alone XML-RPC servers. 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 be given as a keyword-only argument to register *function* under + *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 @@ -209,7 +209,8 @@ example can register functions in a decorator way:: server.register_function(pow) # Register a function under a different name, using - # register_function as a decorator. *name* is keyword-only. + # 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 @@ -300,7 +301,7 @@ requests sent to Python CGI scripts. 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 be given as a keyword-only argument to register *function* under + *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