]> granicus.if.org Git - python/commitdiff
Create xmlrpc package. Issue #2886.
authorGeorg Brandl <georg@python.org>
Mon, 26 May 2008 11:14:17 +0000 (11:14 +0000)
committerGeorg Brandl <georg@python.org>
Mon, 26 May 2008 11:14:17 +0000 (11:14 +0000)
17 files changed:
Doc/library/docxmlrpcserver.rst [deleted file]
Doc/library/internet.rst
Doc/library/persistence.rst
Doc/library/xmlrpc.client.rst [moved from Doc/library/xmlrpclib.rst with 90% similarity]
Doc/library/xmlrpc.server.rst [moved from Doc/library/simplexmlrpcserver.rst with 67% similarity]
Doc/license.rst
Doc/tutorial/stdlib.rst
Lib/DocXMLRPCServer.py [deleted file]
Lib/test/test_anydbm.py [deleted file]
Lib/test/test_docxmlrpc.py
Lib/test/test_xmlrpc.py
Lib/test/test_xmlrpc_net.py
Lib/xmlrpc/__init__.py [new file with mode: 0644]
Lib/xmlrpc/client.py [moved from Lib/xmlrpclib.py with 97% similarity]
Lib/xmlrpc/server.py [moved from Lib/SimpleXMLRPCServer.py with 65% similarity]
Misc/NEWS
Misc/cheatsheet

diff --git a/Doc/library/docxmlrpcserver.rst b/Doc/library/docxmlrpcserver.rst
deleted file mode 100644 (file)
index 8169684..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-
-:mod:`DocXMLRPCServer` --- Self-documenting XML-RPC server
-==========================================================
-
-.. module:: DocXMLRPCServer
-   :synopsis: Self-documenting XML-RPC server implementation.
-.. moduleauthor:: Brian Quinlan <brianq@activestate.com>
-.. sectionauthor:: Brian Quinlan <brianq@activestate.com>
-
-
-The :mod:`DocXMLRPCServer` module extends the classes found in
-:mod:`SimpleXMLRPCServer` to serve HTML documentation in response to HTTP GET
-requests. Servers can either be free standing, using :class:`DocXMLRPCServer`,
-or embedded in a CGI environment, using :class:`DocCGIXMLRPCRequestHandler`.
-
-
-.. class:: DocXMLRPCServer(addr[, requestHandler[, logRequests[, allow_none[,  encoding[, bind_and_activate]]]]])
-
-   Create a new server instance. All parameters have the same meaning as for
-   :class:`SimpleXMLRPCServer.SimpleXMLRPCServer`; *requestHandler* defaults to
-   :class:`DocXMLRPCRequestHandler`.
-
-
-.. class:: DocCGIXMLRPCRequestHandler()
-
-   Create a new instance to handle XML-RPC requests in a CGI environment.
-
-
-.. class:: DocXMLRPCRequestHandler()
-
-   Create a new request handler instance. This request handler supports XML-RPC
-   POST requests, documentation GET requests, and modifies logging so that the
-   *logRequests* parameter to the :class:`DocXMLRPCServer` constructor parameter is
-   honored.
-
-
-.. _doc-xmlrpc-servers:
-
-DocXMLRPCServer Objects
------------------------
-
-The :class:`DocXMLRPCServer` class is derived from
-:class:`SimpleXMLRPCServer.SimpleXMLRPCServer` and provides a means of creating
-self-documenting, stand alone XML-RPC servers. HTTP POST requests are handled as
-XML-RPC method calls. HTTP GET requests are handled by generating pydoc-style
-HTML documentation. This allows a server to provide its own web-based
-documentation.
-
-
-.. method:: DocXMLRPCServer.set_server_title(server_title)
-
-   Set the title used in the generated HTML documentation. This title will be used
-   inside the HTML "title" element.
-
-
-.. method:: DocXMLRPCServer.set_server_name(server_name)
-
-   Set the name used in the generated HTML documentation. This name will appear at
-   the top of the generated documentation inside a "h1" element.
-
-
-.. method:: DocXMLRPCServer.set_server_documentation(server_documentation)
-
-   Set the description used in the generated HTML documentation. This description
-   will appear as a paragraph, below the server name, in the documentation.
-
-
-DocCGIXMLRPCRequestHandler
---------------------------
-
-The :class:`DocCGIXMLRPCRequestHandler` class is derived from
-:class:`SimpleXMLRPCServer.CGIXMLRPCRequestHandler` and provides a means of
-creating self-documenting, XML-RPC CGI scripts. HTTP POST requests are handled
-as XML-RPC method calls. HTTP GET requests are handled by generating pydoc-style
-HTML documentation. This allows a server to provide its own web-based
-documentation.
-
-
-.. method:: DocCGIXMLRPCRequestHandler.set_server_title(server_title)
-
-   Set the title used in the generated HTML documentation. This title will be used
-   inside the HTML "title" element.
-
-
-.. method:: DocCGIXMLRPCRequestHandler.set_server_name(server_name)
-
-   Set the name used in the generated HTML documentation. This name will appear at
-   the top of the generated documentation inside a "h1" element.
-
-
-.. method:: DocCGIXMLRPCRequestHandler.set_server_documentation(server_documentation)
-
-   Set the description used in the generated HTML documentation. This description
-   will appear as a paragraph, below the server name, in the documentation.
-
index 16b0a446a8fa22fd9921bb5b73c86dd60905579c..a5f6d22c481ddd4c5c43ad257c686f7819b13aa8 100644 (file)
@@ -42,6 +42,5 @@ is currently supported on most popular platforms.  Here is an overview:
    cgihttpserver.rst
    cookielib.rst
    cookie.rst
-   xmlrpclib.rst
-   simplexmlrpcserver.rst
-   docxmlrpcserver.rst
+   xmlrpc.client.rst
+   xmlrpc.server.rst
index c5c2aa401e95bef438210b29ab61b565f56cb14d..8d9fa3a3320341aa98ee1411e8267a0f5663c0ec 100644 (file)
@@ -23,4 +23,5 @@ The list of modules described in this chapter is:
    shelve.rst
    marshal.rst
    dbm.rst
+   bsddb.rst
    sqlite3.rst
similarity index 90%
rename from Doc/library/xmlrpclib.rst
rename to Doc/library/xmlrpc.client.rst
index c1f13c389c86a1551aecdcde196cd2d5947db360..7d597501d906f4604eed20d26947cb2885cbdb06 100644 (file)
@@ -1,7 +1,7 @@
-:mod:`xmlrpclib` --- XML-RPC client access
-==========================================
+:mod:`xmlrpc.client` --- XML-RPC client access
+==============================================
 
-.. module:: xmlrpclib
+.. module:: xmlrpc.client
    :synopsis: XML-RPC client access.
 .. moduleauthor:: Fredrik Lundh <fredrik@pythonware.com>
 .. sectionauthor:: Eric S. Raymond <esr@snark.thyrsus.com>
@@ -86,7 +86,7 @@ between conformable Python objects and XML on the wire.
    raise a special :exc:`Fault` instance, used to signal XML-RPC server errors, or
    :exc:`ProtocolError` used to signal an error in the HTTP/HTTPS transport layer.
    Both :exc:`Fault` and :exc:`ProtocolError` derive from a base class called
-   :exc:`Error`.  Note that the xmlrpclib module currently does not marshal
+   :exc:`Error`.  Note that the xmlrpc client module currently does not marshal
    instances of subclasses of builtin types.
 
    When passing strings, characters special to XML such as ``<``, ``>``, and ``&``
@@ -169,28 +169,9 @@ grouped under the reserved :attr:`system` member:
    string may contain HTML markup.
 
 
-.. _boolean-objects:
-
-Boolean Objects
----------------
-
-This class may be initialized from any Python value; the instance returned
-depends only on its truth value.  It supports various Python operators through
-:meth:`__cmp__`, :meth:`__repr__`, :meth:`__int__`, and :meth:`__bool__`
-methods, all implemented in the obvious ways.
-
-It also has the following method, supported mainly for internal use by the
-unmarshalling code:
-
-
-.. method:: Boolean.encode(out)
-
-   Write the XML-RPC encoding of this Boolean item to the out stream object.
-
 A working example follows. The server code::
 
-   import xmlrpclib
-   from SimpleXMLRPCServer import SimpleXMLRPCServer
+   from xmlrpc.server import SimpleXMLRPCServer
 
    def is_even(n):
        return n%2 == 0
@@ -202,9 +183,9 @@ A working example follows. The server code::
 
 The client code for the preceding server::
 
-   import xmlrpclib
+   import xmlrpc.client
 
-   proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
+   proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
    print("3 is even: %s" % str(proxy.is_even(3)))
    print("100 is even: %s" % str(proxy.is_even(100)))
 
@@ -235,12 +216,12 @@ and :meth:`__repr__` methods.
 A working example follows. The server code::
 
    import datetime
-   from SimpleXMLRPCServer import SimpleXMLRPCServer
-   import xmlrpclib
+   from xmlrpc.server import SimpleXMLRPCServer
+   import xmlrpc.client
 
    def today():
        today = datetime.datetime.today()
-       return xmlrpclib.DateTime(today)
+       return xmlrpc.client.DateTime(today)
 
    server = SimpleXMLRPCServer(("localhost", 8000))
    print("Listening on port 8000...")
@@ -249,10 +230,10 @@ A working example follows. The server code::
 
 The client code for the preceding server::
 
-   import xmlrpclib
+   import xmlrpc.client
    import datetime
 
-   proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
+   proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
 
    today = proxy.today()
    # convert the ISO8601 string to a datetime object
@@ -298,12 +279,12 @@ It also supports certain of Python's built-in operators through a
 Example usage of the binary objects.  We're going to transfer an image over
 XMLRPC::
 
-   from SimpleXMLRPCServer import SimpleXMLRPCServer
-   import xmlrpclib
+   from xmlrpc.server import SimpleXMLRPCServer
+   import xmlrpc.client
 
    def python_logo():
         handle = open("python_logo.jpg")
-        return xmlrpclib.Binary(handle.read())
+        return xmlrpc.client.Binary(handle.read())
         handle.close()
 
    server = SimpleXMLRPCServer(("localhost", 8000))
@@ -314,9 +295,9 @@ XMLRPC::
 
 The client gets the image and saves it to a file::
 
-   import xmlrpclib
+   import xmlrpc.client
 
-   proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
+   proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
    handle = open("fetched_python_logo.jpg", "w")
    handle.write(proxy.python_logo().data)
    handle.close()
@@ -342,7 +323,7 @@ objects have the following members:
 In the following example we're going to intentionally cause a :exc:`Fault` by
 returning a complex type object.  The server code::
 
-   from SimpleXMLRPCServer import SimpleXMLRPCServer
+   from xmlrpc.server import SimpleXMLRPCServer
 
    # A marshalling error is going to occur because we're returning a
    # complex number
@@ -357,12 +338,12 @@ returning a complex type object.  The server code::
 
 The client code for the preceding server::
 
-   import xmlrpclib
+   import xmlrpc.client
 
-   proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
+   proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
    try:
        proxy.add(2, 5)
-   except xmlrpclib.Fault, err:
+   except xmlrpc.client.Fault, err:
        print("A fault occured")
        print("Fault code: %d" % err.faultCode)
        print("Fault string: %s" % err.faultString)
@@ -402,14 +383,14 @@ does not exist).  It has the following members:
 In the following example we're going to intentionally cause a :exc:`ProtocolError`
 by providing an invalid URI::
 
-   import xmlrpclib
+   import xmlrpc.client
 
    # create a ServerProxy with an invalid URI
-   proxy = xmlrpclib.ServerProxy("http://invalidaddress/")
+   proxy = xmlrpc.client.ServerProxy("http://invalidaddress/")
 
    try:
        proxy.some_method()
-   except xmlrpclib.ProtocolError, err:
+   except xmlrpc.client.ProtocolError, err:
        print("A protocol error occured")
        print("URL: %s" % err.url)
        print("HTTP/HTTPS headers: %s" % err.headers)
@@ -435,7 +416,7 @@ encapsulate multiple calls to a remote server into a single request.
 
 A usage example of this class follows.  The server code ::
 
-   from SimpleXMLRPCServer import SimpleXMLRPCServer
+   from xmlrpc.server import SimpleXMLRPCServer
 
    def add(x,y):
        return x+y
@@ -461,10 +442,10 @@ A usage example of this class follows.  The server code ::
 
 The client code for the preceding server::
 
-   import xmlrpclib
+   import xmlrpc.client
 
-   proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
-   multicall = xmlrpclib.MultiCall(proxy)
+   proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
+   multicall = xmlrpc.client.MultiCall(proxy)
    multicall.add(7,3)
    multicall.subtract(7,3)
    multicall.multiply(7,3)
@@ -477,13 +458,6 @@ The client code for the preceding server::
 Convenience Functions
 ---------------------
 
-
-.. function:: boolean(value)
-
-   Convert any Python value to one of the XML-RPC Boolean constants, ``True`` or
-   ``False``.
-
-
 .. function:: dumps(params[, methodname[,  methodresponse[, encoding[, allow_none]]]])
 
    Convert *params* into an XML-RPC request. or into a response if *methodresponse*
@@ -513,7 +487,7 @@ Example of Client Usage
 ::
 
    # simple test program (from the XML-RPC specification)
-   from xmlrpclib import ServerProxy, Error
+   from xmlrpc.client import ServerProxy, Error
 
    # server = ServerProxy("http://localhost:8000") # local server
    server = ServerProxy("http://betty.userland.com")
@@ -532,9 +506,9 @@ transport.  The following example shows how:
 
 ::
 
-   import xmlrpclib, httplib
+   import xmlrpc.client, httplib
 
-   class ProxiedTransport(xmlrpclib.Transport):
+   class ProxiedTransport(xmlrpc.client.Transport):
        def set_proxy(self, proxy):
            self.proxy = proxy
        def make_connection(self, host):
@@ -548,7 +522,7 @@ transport.  The following example shows how:
 
    p = ProxiedTransport()
    p.set_proxy('proxy-server:8080')
-   server = xmlrpclib.Server('http://time.xmlrpc.com/RPC2', transport=p)
+   server = xmlrpc.client.Server('http://time.xmlrpc.com/RPC2', transport=p)
    print(server.currentTime.getCurrentTime())
 
 
similarity index 67%
rename from Doc/library/simplexmlrpcserver.rst
rename to Doc/library/xmlrpc.server.rst
index f6b64b3cb3f7fe0261592f85f44921d423404200..1a9c75734d8ca828a8df39251399c1e17309f155 100644 (file)
@@ -1,15 +1,14 @@
+:mod:`xmlrpc.server` --- Basic XML-RPC servers
+==============================================
 
-:mod:`SimpleXMLRPCServer` --- Basic XML-RPC server
-==================================================
-
-.. module:: SimpleXMLRPCServer
-   :synopsis: Basic XML-RPC server implementation.
+.. module:: xmlrpc.server
+   :synopsis: Basic XML-RPC server implementations.
 .. moduleauthor:: Brian Quinlan <brianq@activestate.com>
 .. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
 
 
-The :mod:`SimpleXMLRPCServer` module provides a basic server framework for
-XML-RPC servers written in Python.  Servers can either be free standing, using
+The :mod:`xmlrpc.server` module provides a basic server framework for XML-RPC
+servers written in Python.  Servers can either be free standing, using
 :class:`SimpleXMLRPCServer`, or embedded in a CGI environment, using
 :class:`CGIXMLRPCRequestHandler`.
 
@@ -23,7 +22,7 @@ XML-RPC servers written in Python.  Servers can either be free standing, using
    are passed to the :class:`socketserver.TCPServer` constructor.  If *logRequests*
    is true (the default), requests will be logged; setting this parameter to false
    will turn off logging.   The *allow_none* and *encoding* parameters are passed
-   on to  :mod:`xmlrpclib` and control the XML-RPC responses that will be returned
+   on to  :mod:`xmlrpc.client` and control the XML-RPC responses that will be returned
    from the server. The *bind_and_activate* parameter controls whether
    :meth:`server_bind` and :meth:`server_activate` are called immediately by the
    constructor; it defaults to true. Setting it to false allows code to manipulate
@@ -33,8 +32,8 @@ XML-RPC servers written in Python.  Servers can either be free standing, using
 .. class:: CGIXMLRPCRequestHandler([allow_none[, encoding]])
 
    Create a new instance to handle XML-RPC requests in a CGI environment.  The
-   *allow_none* and *encoding* parameters are passed on to  :mod:`xmlrpclib` and
-   control the XML-RPC responses that will be returned  from the server.
+   *allow_none* and *encoding* parameters are passed on to :mod:`xmlrpc.client`
+   and control the XML-RPC responses that will be returned from the server.
 
 
 .. class:: SimpleXMLRPCRequestHandler()
@@ -115,8 +114,8 @@ SimpleXMLRPCServer Example
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 Server code::
 
-   from SimpleXMLRPCServer import SimpleXMLRPCServer
-   from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
+   from xmlrpc.server import SimpleXMLRPCServer
+   from xmlrpc.server import SimpleXMLRPCRequestHandler
 
    # Restrict to a particular path.
    class RequestHandler(SimpleXMLRPCRequestHandler):
@@ -150,9 +149,9 @@ Server code::
 The following client code will call the methods made available by the preceding
 server::
 
-   import xmlrpclib
+   import xmlrpc.client
 
-   s = xmlrpclib.ServerProxy('http://localhost:8000')
+   s = xmlrpc.client.ServerProxy('http://localhost:8000')
    print(s.pow(2,3))  # Returns 2**3 = 8
    print(s.add(2,3))  # Returns 5
    print(s.mul(5,2))  # Returns 5*2 = 10
@@ -220,3 +219,89 @@ Example::
    handler.register_instance(MyFuncs())
    handler.handle_request()
 
+
+Documenting XMLRPC server
+-------------------------
+
+These classes extend the above classes to serve HTML documentation in response
+to HTTP GET requests.  Servers can either be free standing, using
+:class:`DocXMLRPCServer`, or embedded in a CGI environment, using
+:class:`DocCGIXMLRPCRequestHandler`.
+
+
+.. class:: DocXMLRPCServer(addr[, requestHandler[, logRequests[, allow_none[,  encoding[, bind_and_activate]]]]])
+
+   Create a new server instance. All parameters have the same meaning as for
+   :class:`SimpleXMLRPCServer`; *requestHandler* defaults to
+   :class:`DocXMLRPCRequestHandler`.
+
+
+.. class:: DocCGIXMLRPCRequestHandler()
+
+   Create a new instance to handle XML-RPC requests in a CGI environment.
+
+
+.. class:: DocXMLRPCRequestHandler()
+
+   Create a new request handler instance. This request handler supports XML-RPC
+   POST requests, documentation GET requests, and modifies logging so that the
+   *logRequests* parameter to the :class:`DocXMLRPCServer` constructor parameter is
+   honored.
+
+
+.. _doc-xmlrpc-servers:
+
+DocXMLRPCServer Objects
+-----------------------
+
+The :class:`DocXMLRPCServer` class is derived from :class:`SimpleXMLRPCServer`
+and provides a means of creating self-documenting, stand alone XML-RPC
+servers. HTTP POST requests are handled as XML-RPC method calls. HTTP GET
+requests are handled by generating pydoc-style HTML documentation. This allows a
+server to provide its own web-based documentation.
+
+
+.. method:: DocXMLRPCServer.set_server_title(server_title)
+
+   Set the title used in the generated HTML documentation. This title will be used
+   inside the HTML "title" element.
+
+
+.. method:: DocXMLRPCServer.set_server_name(server_name)
+
+   Set the name used in the generated HTML documentation. This name will appear at
+   the top of the generated documentation inside a "h1" element.
+
+
+.. method:: DocXMLRPCServer.set_server_documentation(server_documentation)
+
+   Set the description used in the generated HTML documentation. This description
+   will appear as a paragraph, below the server name, in the documentation.
+
+
+DocCGIXMLRPCRequestHandler
+--------------------------
+
+The :class:`DocCGIXMLRPCRequestHandler` class is derived from
+:class:`CGIXMLRPCRequestHandler` and provides a means of creating
+self-documenting, XML-RPC CGI scripts. HTTP POST requests are handled as XML-RPC
+method calls. HTTP GET requests are handled by generating pydoc-style HTML
+documentation. This allows a server to provide its own web-based documentation.
+
+
+.. method:: DocCGIXMLRPCRequestHandler.set_server_title(server_title)
+
+   Set the title used in the generated HTML documentation. This title will be used
+   inside the HTML "title" element.
+
+
+.. method:: DocCGIXMLRPCRequestHandler.set_server_name(server_name)
+
+   Set the name used in the generated HTML documentation. This name will appear at
+   the top of the generated documentation inside a "h1" element.
+
+
+.. method:: DocCGIXMLRPCRequestHandler.set_server_documentation(server_documentation)
+
+   Set the description used in the generated HTML documentation. This description
+   will appear as a paragraph, below the server name, in the documentation.
index 05962e96ce47724782357b0b3ef2d830d7519787..ed399dc23d726037c27f457d8609d8e07dc019dc 100644 (file)
@@ -570,7 +570,7 @@ The :mod:`uu` module contains the following notice::
 XML Remote Procedure Calls
 --------------------------
 
-The :mod:`xmlrpclib` module contains the following notice::
+The :mod:`xmlrpc.client` module contains the following notice::
 
        The XML-RPC client interface is
 
index 725817cbf083d96b85f6195d4b827cc87080f619..66e73a915c292d45ee250623affb216b4c840435 100644 (file)
@@ -294,7 +294,7 @@ Batteries Included
 Python has a "batteries included" philosophy.  This is best seen through the
 sophisticated and robust capabilities of its larger packages. For example:
 
-* The :mod:`xmlrpclib` and :mod:`SimpleXMLRPCServer` modules make implementing
+* The :mod:`xmlrpc.client` and :mod:`xmlrpc.server` modules make implementing
   remote procedure calls into an almost trivial task.  Despite the modules
   names, no direct knowledge or handling of XML is needed.
 
diff --git a/Lib/DocXMLRPCServer.py b/Lib/DocXMLRPCServer.py
deleted file mode 100644 (file)
index 246fd74..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-"""Self documenting XML-RPC Server.
-
-This module can be used to create XML-RPC servers that
-serve pydoc-style documentation in response to HTTP
-GET requests. This documentation is dynamically generated
-based on the functions and methods registered with the
-server.
-
-This module is built upon the pydoc and SimpleXMLRPCServer
-modules.
-"""
-
-import pydoc
-import inspect
-import re
-import sys
-
-from SimpleXMLRPCServer import (SimpleXMLRPCServer,
-            SimpleXMLRPCRequestHandler,
-            CGIXMLRPCRequestHandler,
-            resolve_dotted_attribute)
-
-class ServerHTMLDoc(pydoc.HTMLDoc):
-    """Class used to generate pydoc HTML document for a server"""
-
-    def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
-        """Mark up some plain text, given a context of symbols to look for.
-        Each context dictionary maps object names to anchor names."""
-        escape = escape or self.escape
-        results = []
-        here = 0
-
-        # XXX Note that this regular expression does not allow for the
-        # hyperlinking of arbitrary strings being used as method
-        # names. Only methods with names consisting of word characters
-        # and '.'s are hyperlinked.
-        pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
-                                r'RFC[- ]?(\d+)|'
-                                r'PEP[- ]?(\d+)|'
-                                r'(self\.)?((?:\w|\.)+))\b')
-        while 1:
-            match = pattern.search(text, here)
-            if not match: break
-            start, end = match.span()
-            results.append(escape(text[here:start]))
-
-            all, scheme, rfc, pep, selfdot, name = match.groups()
-            if scheme:
-                url = escape(all).replace('"', '&quot;')
-                results.append('<a href="%s">%s</a>' % (url, url))
-            elif rfc:
-                url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
-                results.append('<a href="%s">%s</a>' % (url, escape(all)))
-            elif pep:
-                url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
-                results.append('<a href="%s">%s</a>' % (url, escape(all)))
-            elif text[end:end+1] == '(':
-                results.append(self.namelink(name, methods, funcs, classes))
-            elif selfdot:
-                results.append('self.<strong>%s</strong>' % name)
-            else:
-                results.append(self.namelink(name, classes))
-            here = end
-        results.append(escape(text[here:]))
-        return ''.join(results)
-
-    def docroutine(self, object, name, mod=None,
-                   funcs={}, classes={}, methods={}, cl=None):
-        """Produce HTML documentation for a function or method object."""
-
-        anchor = (cl and cl.__name__ or '') + '-' + name
-        note = ''
-
-        title = '<a name="%s"><strong>%s</strong></a>' % (
-            self.escape(anchor), self.escape(name))
-
-        if inspect.ismethod(object):
-            args, varargs, varkw, defaults = inspect.getargspec(object)
-            # exclude the argument bound to the instance, it will be
-            # confusing to the non-Python user
-            argspec = inspect.formatargspec (
-                    args[1:],
-                    varargs,
-                    varkw,
-                    defaults,
-                    formatvalue=self.formatvalue
-                )
-        elif inspect.isfunction(object):
-            args, varargs, varkw, defaults = inspect.getargspec(object)
-            argspec = inspect.formatargspec(
-                args, varargs, varkw, defaults, formatvalue=self.formatvalue)
-        else:
-            argspec = '(...)'
-
-        if isinstance(object, tuple):
-            argspec = object[0] or argspec
-            docstring = object[1] or ""
-        else:
-            docstring = pydoc.getdoc(object)
-
-        decl = title + argspec + (note and self.grey(
-               '<font face="helvetica, arial">%s</font>' % note))
-
-        doc = self.markup(
-            docstring, self.preformat, funcs, classes, methods)
-        doc = doc and '<dd><tt>%s</tt></dd>' % doc
-        return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
-
-    def docserver(self, server_name, package_documentation, methods):
-        """Produce HTML documentation for an XML-RPC server."""
-
-        fdict = {}
-        for key, value in methods.items():
-            fdict[key] = '#-' + key
-            fdict[value] = fdict[key]
-
-        server_name = self.escape(server_name)
-        head = '<big><big><strong>%s</strong></big></big>' % server_name
-        result = self.heading(head, '#ffffff', '#7799ee')
-
-        doc = self.markup(package_documentation, self.preformat, fdict)
-        doc = doc and '<tt>%s</tt>' % doc
-        result = result + '<p>%s</p>\n' % doc
-
-        contents = []
-        method_items = sorted(methods.items())
-        for key, value in method_items:
-            contents.append(self.docroutine(value, key, funcs=fdict))
-        result = result + self.bigsection(
-            'Methods', '#ffffff', '#eeaa77', ''.join(contents))
-
-        return result
-
-class XMLRPCDocGenerator:
-    """Generates documentation for an XML-RPC server.
-
-    This class is designed as mix-in and should not
-    be constructed directly.
-    """
-
-    def __init__(self):
-        # setup variables used for HTML documentation
-        self.server_name = 'XML-RPC Server Documentation'
-        self.server_documentation = \
-            "This server exports the following methods through the XML-RPC "\
-            "protocol."
-        self.server_title = 'XML-RPC Server Documentation'
-
-    def set_server_title(self, server_title):
-        """Set the HTML title of the generated server documentation"""
-
-        self.server_title = server_title
-
-    def set_server_name(self, server_name):
-        """Set the name of the generated HTML server documentation"""
-
-        self.server_name = server_name
-
-    def set_server_documentation(self, server_documentation):
-        """Set the documentation string for the entire server."""
-
-        self.server_documentation = server_documentation
-
-    def generate_html_documentation(self):
-        """generate_html_documentation() => html documentation for the server
-
-        Generates HTML documentation for the server using introspection for
-        installed functions and instances that do not implement the
-        _dispatch method. Alternatively, instances can choose to implement
-        the _get_method_argstring(method_name) method to provide the
-        argument string used in the documentation and the
-        _methodHelp(method_name) method to provide the help text used
-        in the documentation."""
-
-        methods = {}
-
-        for method_name in self.system_listMethods():
-            if method_name in self.funcs:
-                method = self.funcs[method_name]
-            elif self.instance is not None:
-                method_info = [None, None] # argspec, documentation
-                if hasattr(self.instance, '_get_method_argstring'):
-                    method_info[0] = self.instance._get_method_argstring(method_name)
-                if hasattr(self.instance, '_methodHelp'):
-                    method_info[1] = self.instance._methodHelp(method_name)
-
-                method_info = tuple(method_info)
-                if method_info != (None, None):
-                    method = method_info
-                elif not hasattr(self.instance, '_dispatch'):
-                    try:
-                        method = resolve_dotted_attribute(
-                                    self.instance,
-                                    method_name
-                                    )
-                    except AttributeError:
-                        method = method_info
-                else:
-                    method = method_info
-            else:
-                assert 0, "Could not find method in self.functions and no "\
-                          "instance installed"
-
-            methods[method_name] = method
-
-        documenter = ServerHTMLDoc()
-        documentation = documenter.docserver(
-                                self.server_name,
-                                self.server_documentation,
-                                methods
-                            )
-
-        return documenter.page(self.server_title, documentation)
-
-class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
-    """XML-RPC and documentation request handler class.
-
-    Handles all HTTP POST requests and attempts to decode them as
-    XML-RPC requests.
-
-    Handles all HTTP GET requests and interprets them as requests
-    for documentation.
-    """
-
-    def do_GET(self):
-        """Handles the HTTP GET request.
-
-        Interpret all HTTP GET requests as requests for server
-        documentation.
-        """
-        # Check that the path is legal
-        if not self.is_rpc_path_valid():
-            self.report_404()
-            return
-
-        response = self.server.generate_html_documentation()
-        self.send_response(200)
-        self.send_header("Content-type", "text/html")
-        self.send_header("Content-length", str(len(response)))
-        self.end_headers()
-        self.wfile.write(response.encode())
-
-        # shut down the connection
-        self.wfile.flush()
-        self.connection.shutdown(1)
-
-class DocXMLRPCServer(  SimpleXMLRPCServer,
-                        XMLRPCDocGenerator):
-    """XML-RPC and HTML documentation server.
-
-    Adds the ability to serve server documentation to the capabilities
-    of SimpleXMLRPCServer.
-    """
-
-    def __init__(self, addr, requestHandler=DocXMLRPCRequestHandler,
-                 logRequests=1, allow_none=False, encoding=None,
-                 bind_and_activate=True):
-        SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests,
-                                    allow_none, encoding, bind_and_activate)
-        XMLRPCDocGenerator.__init__(self)
-
-class DocCGIXMLRPCRequestHandler(   CGIXMLRPCRequestHandler,
-                                    XMLRPCDocGenerator):
-    """Handler for XML-RPC data and documentation requests passed through
-    CGI"""
-
-    def handle_get(self):
-        """Handles the HTTP GET request.
-
-        Interpret all HTTP GET requests as requests for server
-        documentation.
-        """
-
-        response = self.generate_html_documentation()
-
-        print('Content-Type: text/html')
-        print('Content-Length: %d' % len(response))
-        print()
-        sys.stdout.write(response)
-
-    def __init__(self):
-        CGIXMLRPCRequestHandler.__init__(self)
-        XMLRPCDocGenerator.__init__(self)
diff --git a/Lib/test/test_anydbm.py b/Lib/test/test_anydbm.py
deleted file mode 100644 (file)
index aab1388..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-#! /usr/bin/env python
-"""Test script for the dbm.open function based on testdumbdbm.py"""
-
-import os
-import unittest
-import dbm
-import glob
-import test.support
-
-_fname = test.support.TESTFN
-
-#
-# Iterates over every database module supported by dbm currently available,
-# setting dbm to use each in turn, and yielding that module
-#
-def dbm_iterator():
-    old_default = dbm._defaultmod
-    for module in dbm._modules.values():
-        dbm._defaultmod = module
-        yield module
-    dbm._defaultmod = old_default
-
-#
-# Clean up all scratch databases we might have created during testing
-#
-def delete_files():
-    # we don't know the precise name the underlying database uses
-    # so we use glob to locate all names
-    for f in glob.glob(_fname + "*"):
-        test.support.unlink(f)
-
-
-class AnyDBMTestCase(unittest.TestCase):
-    _dict = {'0': b'',
-             'a': b'Python:',
-             'b': b'Programming',
-             'c': b'the',
-             'd': b'way',
-             'f': b'Guido',
-             'g': b'intended',
-             }
-
-    def __init__(self, *args):
-        unittest.TestCase.__init__(self, *args)
-
-    def test_anydbm_creation(self):
-        f = dbm.open(_fname, 'c')
-        self.assertEqual(list(f.keys()), [])
-        for key in self._dict:
-            f[key.encode("ascii")] = self._dict[key]
-        self.read_helper(f)
-        f.close()
-
-    def test_anydbm_modification(self):
-        self.init_db()
-        f = dbm.open(_fname, 'c')
-        self._dict['g'] = f[b'g'] = b"indented"
-        self.read_helper(f)
-        f.close()
-
-    def test_anydbm_read(self):
-        self.init_db()
-        f = dbm.open(_fname, 'r')
-        self.read_helper(f)
-        f.close()
-
-    def test_anydbm_keys(self):
-        self.init_db()
-        f = dbm.open(_fname, 'r')
-        keys = self.keys_helper(f)
-        f.close()
-
-    def test_anydbm_access(self):
-        self.init_db()
-        f = dbm.open(_fname, 'r')
-        key = "a".encode("ascii")
-        assert(key in f)
-        assert(f[key] == b"Python:")
-        f.close()
-
-    def read_helper(self, f):
-        keys = self.keys_helper(f)
-        for key in self._dict:
-            self.assertEqual(self._dict[key], f[key.encode("ascii")])
-
-    def init_db(self):
-        f = dbm.open(_fname, 'n')
-        for k in self._dict:
-            f[k.encode("ascii")] = self._dict[k]
-        f.close()
-
-    def keys_helper(self, f):
-        keys = sorted(k.decode("ascii") for k in f.keys())
-        dkeys = sorted(self._dict.keys())
-        self.assertEqual(keys, dkeys)
-        return keys
-
-    def tearDown(self):
-        delete_files()
-
-    def setUp(self):
-        delete_files()
-
-
-class WhichDBTestCase(unittest.TestCase):
-    # Actual test methods are added to namespace after class definition.
-    def __init__(self, *args):
-        unittest.TestCase.__init__(self, *args)
-
-    def test_whichdb(self):
-        for module in dbm_iterator():
-            # Check whether whichdb correctly guesses module name
-            # for databases opened with "module" module.
-            # Try with empty files first
-            name = module.__name__
-            if name == 'dbm.dumb':
-                continue   # whichdb can't support dbm.dumb
-            test.support.unlink(_fname)
-            f = module.open(_fname, 'c')
-            f.close()
-            self.assertEqual(name, dbm.whichdb(_fname))
-            # Now add a key
-            f = module.open(_fname, 'w')
-            f[b"1"] = b"1"
-            # and test that we can find it
-            self.assertTrue(b"1" in f)
-            # and read it
-            self.assertTrue(f[b"1"] == b"1")
-            f.close()
-            self.assertEqual(name, dbm.whichdb(_fname))
-
-    def tearDown(self):
-        delete_files()
-
-    def setUp(self):
-        delete_files()
-
-
-def test_main():
-    try:
-        for module in dbm_iterator():
-            test.support.run_unittest(AnyDBMTestCase, WhichDBTestCase)
-    finally:
-        delete_files()
-
-if __name__ == "__main__":
-    test_main()
index 2af20716b0464440df92b713bdbbdf0982ebbb63..9cb9ffbd485a789bacce599c96dffce9b80bc0d3 100644 (file)
@@ -1,10 +1,9 @@
-from DocXMLRPCServer import DocXMLRPCServer
+from xmlrpc.server import DocXMLRPCServer
 import httplib
 from test import support
 import threading
 import time
 import unittest
-import xmlrpclib
 
 PORT = None
 
index cad2b9dc3b0f6f04ff5bec46c02f0409e1483b7c..25a9c9d2814385f57699544688940b73c8ffe0f4 100644 (file)
@@ -3,8 +3,8 @@ import datetime
 import sys
 import time
 import unittest
-import xmlrpclib
-import SimpleXMLRPCServer
+import xmlrpc.client as xmlrpclib
+import xmlrpc.server
 import threading
 import mimetools
 import httplib
@@ -160,9 +160,9 @@ class FaultTestCase(unittest.TestCase):
         # this will raise AttirebuteError because code don't want us to use
         # private methods
         self.assertRaises(AttributeError,
-                          SimpleXMLRPCServer.resolve_dotted_attribute, str, '__add')
+                          xmlrpc.server.resolve_dotted_attribute, str, '__add')
 
-        self.assert_(SimpleXMLRPCServer.resolve_dotted_attribute(str, 'title'))
+        self.assert_(xmlrpc.server.resolve_dotted_attribute(str, 'title'))
 
 class DateTimeTestCase(unittest.TestCase):
     def test_default(self):
@@ -249,7 +249,7 @@ def http_server(evt, numrequests):
         '''This is my function'''
         return True
 
-    class MyXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
+    class MyXMLRPCServer(xmlrpc.server.SimpleXMLRPCServer):
         def get_request(self):
             # Ensure the socket is always non-blocking.  On Linux, socket
             # attributes are not inherited like they are on *BSD and Windows.
@@ -306,7 +306,7 @@ def is_unavailable_exception(e):
 class SimpleServerTestCase(unittest.TestCase):
     def setUp(self):
         # enable traceback reporting
-        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
+        xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = True
 
         self.evt = threading.Event()
         # start server thread to handle requests
@@ -326,7 +326,7 @@ class SimpleServerTestCase(unittest.TestCase):
             raise RuntimeError("timeout reached, test has failed")
 
         # disable traceback reporting
-        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
+        xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = False
 
     def test_simple1(self):
         try:
@@ -443,9 +443,9 @@ class SimpleServerTestCase(unittest.TestCase):
     def test_dotted_attribute(self):
         # Raises an AttributeError because private methods are not allowed.
         self.assertRaises(AttributeError,
-                          SimpleXMLRPCServer.resolve_dotted_attribute, str, '__add')
+                          xmlrpc.server.resolve_dotted_attribute, str, '__add')
 
-        self.assert_(SimpleXMLRPCServer.resolve_dotted_attribute(str, 'title'))
+        self.assert_(xmlrpc.server.resolve_dotted_attribute(str, 'title'))
         # Get the test to run faster by sending a request with test_simple1.
         # This avoids waiting for the socket timeout.
         self.test_simple1()
@@ -475,17 +475,17 @@ class FailingServerTestCase(unittest.TestCase):
         # wait on the server thread to terminate
         self.evt.wait()
         # reset flag
-        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
+        xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = False
         # reset message class
-        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message
+        xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message
 
     def test_basic(self):
         # check that flag is false by default
-        flagval = SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header
+        flagval = xmlrpc.server.SimpleXMLRPCServer._send_traceback_header
         self.assertEqual(flagval, False)
 
         # enable traceback reporting
-        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
+        xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = True
 
         # test a call that shouldn't fail just as a smoke test
         try:
@@ -499,7 +499,7 @@ class FailingServerTestCase(unittest.TestCase):
 
     def test_fail_no_info(self):
         # use the broken message class
-        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
+        xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
 
         try:
             p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
@@ -515,11 +515,11 @@ class FailingServerTestCase(unittest.TestCase):
 
     def test_fail_with_info(self):
         # use the broken message class
-        SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
+        xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
 
         # Check that errors in the server send back exception/traceback
         # info when flag is set
-        SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
+        xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = True
 
         try:
             p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
@@ -536,7 +536,7 @@ class FailingServerTestCase(unittest.TestCase):
 
 class CGIHandlerTestCase(unittest.TestCase):
     def setUp(self):
-        self.cgi = SimpleXMLRPCServer.CGIXMLRPCRequestHandler()
+        self.cgi = xmlrpc.server.CGIXMLRPCRequestHandler()
 
     def tearDown(self):
         self.cgi = None
index 1f8dd5d1e53fe733001793b0df2e8cf6096b4732..25252546d2e4c1e4353353e85bfc7703ef496010 100644 (file)
@@ -6,7 +6,7 @@ import sys
 import unittest
 from test import support
 
-import xmlrpclib
+import xmlrpclib.client as xmlrpclib
 
 class CurrentTimeTest(unittest.TestCase):
 
diff --git a/Lib/xmlrpc/__init__.py b/Lib/xmlrpc/__init__.py
new file mode 100644 (file)
index 0000000..196d378
--- /dev/null
@@ -0,0 +1 @@
+# This directory is a Python package.
similarity index 97%
rename from Lib/xmlrpclib.py
rename to Lib/xmlrpc/client.py
index 522df4d0ef4a73e2b458e3d61afd0ea6c90bd256..138d86d71a0f2247c27fef1c6244c2f6abbaf237 100644 (file)
@@ -108,7 +108,6 @@ Exported classes:
   ServerProxy    Represents a logical connection to an XML-RPC server
 
   MultiCall      Executor of boxcared xmlrpc requests
-  Boolean        boolean wrapper to generate a "boolean" XML-RPC value
   DateTime       dateTime wrapper for an ISO 8601 string or time tuple or
                  localtime integer value to generate a "dateTime.iso8601"
                  XML-RPC value
@@ -127,7 +126,6 @@ Exported constants:
 
 Exported functions:
 
-  boolean        Convert any Python value to an XML-RPC boolean
   getparser      Create instance of the fastest available parser & attach
                  to an unmarshalling object
   dumps          Convert an argument tuple or a Fault instance to an XML-RPC
@@ -147,11 +145,6 @@ try:
 except ImportError:
     datetime = None
 
-try:
-    _bool_is_builtin = False.__class__.__name__ == "bool"
-except NameError:
-    _bool_is_builtin = 0
-
 def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
     # decode non-ascii string (if possible)
     if encoding and is8bit(data):
@@ -265,12 +258,7 @@ class Fault(Error):
 # Special values
 
 ##
-# Wrapper for XML-RPC boolean values.  Use the xmlrpclib.True and
-# xmlrpclib.False constants, or the xmlrpclib.boolean() function, to
-# generate boolean XML-RPC values.
-#
-# @param value A boolean value.  Any true value is interpreted as True,
-#              all other values are interpreted as False.
+# Backwards compatibility
 
 boolean = Boolean = bool
 
@@ -451,26 +439,10 @@ def _binary(data):
     return value
 
 WRAPPERS = (DateTime, Binary)
-if not _bool_is_builtin:
-    WRAPPERS = WRAPPERS + (Boolean,)
 
 # --------------------------------------------------------------------
 # XML parsers
 
-try:
-    # optional xmlrpclib accelerator
-    import _xmlrpclib
-    FastParser = _xmlrpclib.Parser
-    FastUnmarshaller = _xmlrpclib.Unmarshaller
-except (AttributeError, ImportError):
-    FastParser = FastUnmarshaller = None
-
-try:
-    import _xmlrpclib
-    FastMarshaller = _xmlrpclib.Marshaller
-except (AttributeError, ImportError):
-    FastMarshaller = None
-
 #
 # the SGMLOP parser is about 15x faster than Python's builtin
 # XML parser.  SGMLOP sources can be downloaded from:
@@ -640,12 +612,11 @@ class Marshaller:
         write("</int></value>\n")
     #dispatch[int] = dump_int
 
-    if _bool_is_builtin:
-        def dump_bool(self, value, write):
-            write("<value><boolean>")
-            write(value and "1" or "0")
-            write("</boolean></value>\n")
-        dispatch[bool] = dump_bool
+    def dump_bool(self, value, write):
+        write("<value><boolean>")
+        write(value and "1" or "0")
+        write("</boolean></value>\n")
+    dispatch[bool] = dump_bool
 
     def dump_long(self, value, write):
         if value > MAXINT or value < MININT:
@@ -968,6 +939,8 @@ class MultiCall:
 # --------------------------------------------------------------------
 # convenience functions
 
+FastMarshaller = FastParser = FastUnmarshaller = None
+
 ##
 # Create a parser object, and connect it to an unmarshalling instance.
 # This function picks the fastest available XML parser.
similarity index 65%
rename from Lib/SimpleXMLRPCServer.py
rename to Lib/xmlrpc/server.py
index a9851535aba0917283935220623ad919f82d41cd..9668c8cbea7e64ea7685fd60b2b9c40723b5ac58 100644 (file)
@@ -1,4 +1,4 @@
-"""Simple XML-RPC Server.
+"""XML-RPC Servers.
 
 This module can be used to create simple XML-RPC servers
 by creating a server and either installing functions, a
@@ -8,6 +8,12 @@ class.
 It can also be used to handle XML-RPC requests in a CGI
 environment using CGIXMLRPCRequestHandler.
 
+The Doc* classes can be used to create XML-RPC servers that
+serve pydoc-style documentation in response to HTTP
+GET requests. This documentation is dynamically generated
+based on the functions and methods registered with the
+server.
+
 A list of possible usage patterns follows:
 
 1. Install functions:
@@ -98,12 +104,14 @@ server.handle_request()
 # Written by Brian Quinlan (brian@sweetapp.com).
 # Based on code written by Fredrik Lundh.
 
-import xmlrpclib
-from xmlrpclib import Fault
+from xmlrpc.client import Fault, dumps, loads
 import socketserver
 import BaseHTTPServer
 import sys
 import os
+import re
+import pydoc
+import inspect
 import traceback
 try:
     import fcntl
@@ -235,7 +243,7 @@ class SimpleXMLRPCDispatcher:
         """
 
         try:
-            params, method = xmlrpclib.loads(data)
+            params, method = loads(data)
 
             # generate response
             if dispatch_method is not None:
@@ -244,16 +252,16 @@ class SimpleXMLRPCDispatcher:
                 response = self._dispatch(method, params)
             # wrap response in a singleton tuple
             response = (response,)
-            response = xmlrpclib.dumps(response, methodresponse=1,
-                                       allow_none=self.allow_none, encoding=self.encoding)
+            response = dumps(response, methodresponse=1,
+                             allow_none=self.allow_none, encoding=self.encoding)
         except Fault as fault:
-            response = xmlrpclib.dumps(fault, allow_none=self.allow_none,
-                                       encoding=self.encoding)
+            response = dumps(fault, allow_none=self.allow_none,
+                             encoding=self.encoding)
         except:
             # report exception back to server
             exc_type, exc_value, exc_tb = sys.exc_info()
-            response = xmlrpclib.dumps(
-                xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value)),
+            response = dumps(
+                Fault(1, "%s:%s" % (exc_type, exc_value)),
                 encoding=self.encoding, allow_none=self.allow_none,
                 )
 
@@ -585,6 +593,273 @@ class CGIXMLRPCRequestHandler(SimpleXMLRPCDispatcher):
 
             self.handle_xmlrpc(request_text)
 
+
+# -----------------------------------------------------------------------------
+# Self documenting XML-RPC Server.
+
+class ServerHTMLDoc(pydoc.HTMLDoc):
+    """Class used to generate pydoc HTML document for a server"""
+
+    def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
+        """Mark up some plain text, given a context of symbols to look for.
+        Each context dictionary maps object names to anchor names."""
+        escape = escape or self.escape
+        results = []
+        here = 0
+
+        # XXX Note that this regular expression does not allow for the
+        # hyperlinking of arbitrary strings being used as method
+        # names. Only methods with names consisting of word characters
+        # and '.'s are hyperlinked.
+        pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
+                                r'RFC[- ]?(\d+)|'
+                                r'PEP[- ]?(\d+)|'
+                                r'(self\.)?((?:\w|\.)+))\b')
+        while 1:
+            match = pattern.search(text, here)
+            if not match: break
+            start, end = match.span()
+            results.append(escape(text[here:start]))
+
+            all, scheme, rfc, pep, selfdot, name = match.groups()
+            if scheme:
+                url = escape(all).replace('"', '&quot;')
+                results.append('<a href="%s">%s</a>' % (url, url))
+            elif rfc:
+                url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
+                results.append('<a href="%s">%s</a>' % (url, escape(all)))
+            elif pep:
+                url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
+                results.append('<a href="%s">%s</a>' % (url, escape(all)))
+            elif text[end:end+1] == '(':
+                results.append(self.namelink(name, methods, funcs, classes))
+            elif selfdot:
+                results.append('self.<strong>%s</strong>' % name)
+            else:
+                results.append(self.namelink(name, classes))
+            here = end
+        results.append(escape(text[here:]))
+        return ''.join(results)
+
+    def docroutine(self, object, name, mod=None,
+                   funcs={}, classes={}, methods={}, cl=None):
+        """Produce HTML documentation for a function or method object."""
+
+        anchor = (cl and cl.__name__ or '') + '-' + name
+        note = ''
+
+        title = '<a name="%s"><strong>%s</strong></a>' % (
+            self.escape(anchor), self.escape(name))
+
+        if inspect.ismethod(object):
+            args, varargs, varkw, defaults = inspect.getargspec(object)
+            # exclude the argument bound to the instance, it will be
+            # confusing to the non-Python user
+            argspec = inspect.formatargspec (
+                    args[1:],
+                    varargs,
+                    varkw,
+                    defaults,
+                    formatvalue=self.formatvalue
+                )
+        elif inspect.isfunction(object):
+            args, varargs, varkw, defaults = inspect.getargspec(object)
+            argspec = inspect.formatargspec(
+                args, varargs, varkw, defaults, formatvalue=self.formatvalue)
+        else:
+            argspec = '(...)'
+
+        if isinstance(object, tuple):
+            argspec = object[0] or argspec
+            docstring = object[1] or ""
+        else:
+            docstring = pydoc.getdoc(object)
+
+        decl = title + argspec + (note and self.grey(
+               '<font face="helvetica, arial">%s</font>' % note))
+
+        doc = self.markup(
+            docstring, self.preformat, funcs, classes, methods)
+        doc = doc and '<dd><tt>%s</tt></dd>' % doc
+        return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
+
+    def docserver(self, server_name, package_documentation, methods):
+        """Produce HTML documentation for an XML-RPC server."""
+
+        fdict = {}
+        for key, value in methods.items():
+            fdict[key] = '#-' + key
+            fdict[value] = fdict[key]
+
+        server_name = self.escape(server_name)
+        head = '<big><big><strong>%s</strong></big></big>' % server_name
+        result = self.heading(head, '#ffffff', '#7799ee')
+
+        doc = self.markup(package_documentation, self.preformat, fdict)
+        doc = doc and '<tt>%s</tt>' % doc
+        result = result + '<p>%s</p>\n' % doc
+
+        contents = []
+        method_items = sorted(methods.items())
+        for key, value in method_items:
+            contents.append(self.docroutine(value, key, funcs=fdict))
+        result = result + self.bigsection(
+            'Methods', '#ffffff', '#eeaa77', ''.join(contents))
+
+        return result
+
+class XMLRPCDocGenerator:
+    """Generates documentation for an XML-RPC server.
+
+    This class is designed as mix-in and should not
+    be constructed directly.
+    """
+
+    def __init__(self):
+        # setup variables used for HTML documentation
+        self.server_name = 'XML-RPC Server Documentation'
+        self.server_documentation = \
+            "This server exports the following methods through the XML-RPC "\
+            "protocol."
+        self.server_title = 'XML-RPC Server Documentation'
+
+    def set_server_title(self, server_title):
+        """Set the HTML title of the generated server documentation"""
+
+        self.server_title = server_title
+
+    def set_server_name(self, server_name):
+        """Set the name of the generated HTML server documentation"""
+
+        self.server_name = server_name
+
+    def set_server_documentation(self, server_documentation):
+        """Set the documentation string for the entire server."""
+
+        self.server_documentation = server_documentation
+
+    def generate_html_documentation(self):
+        """generate_html_documentation() => html documentation for the server
+
+        Generates HTML documentation for the server using introspection for
+        installed functions and instances that do not implement the
+        _dispatch method. Alternatively, instances can choose to implement
+        the _get_method_argstring(method_name) method to provide the
+        argument string used in the documentation and the
+        _methodHelp(method_name) method to provide the help text used
+        in the documentation."""
+
+        methods = {}
+
+        for method_name in self.system_listMethods():
+            if method_name in self.funcs:
+                method = self.funcs[method_name]
+            elif self.instance is not None:
+                method_info = [None, None] # argspec, documentation
+                if hasattr(self.instance, '_get_method_argstring'):
+                    method_info[0] = self.instance._get_method_argstring(method_name)
+                if hasattr(self.instance, '_methodHelp'):
+                    method_info[1] = self.instance._methodHelp(method_name)
+
+                method_info = tuple(method_info)
+                if method_info != (None, None):
+                    method = method_info
+                elif not hasattr(self.instance, '_dispatch'):
+                    try:
+                        method = resolve_dotted_attribute(
+                                    self.instance,
+                                    method_name
+                                    )
+                    except AttributeError:
+                        method = method_info
+                else:
+                    method = method_info
+            else:
+                assert 0, "Could not find method in self.functions and no "\
+                          "instance installed"
+
+            methods[method_name] = method
+
+        documenter = ServerHTMLDoc()
+        documentation = documenter.docserver(
+                                self.server_name,
+                                self.server_documentation,
+                                methods
+                            )
+
+        return documenter.page(self.server_title, documentation)
+
+class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
+    """XML-RPC and documentation request handler class.
+
+    Handles all HTTP POST requests and attempts to decode them as
+    XML-RPC requests.
+
+    Handles all HTTP GET requests and interprets them as requests
+    for documentation.
+    """
+
+    def do_GET(self):
+        """Handles the HTTP GET request.
+
+        Interpret all HTTP GET requests as requests for server
+        documentation.
+        """
+        # Check that the path is legal
+        if not self.is_rpc_path_valid():
+            self.report_404()
+            return
+
+        response = self.server.generate_html_documentation()
+        self.send_response(200)
+        self.send_header("Content-type", "text/html")
+        self.send_header("Content-length", str(len(response)))
+        self.end_headers()
+        self.wfile.write(response.encode())
+
+        # shut down the connection
+        self.wfile.flush()
+        self.connection.shutdown(1)
+
+class DocXMLRPCServer(  SimpleXMLRPCServer,
+                        XMLRPCDocGenerator):
+    """XML-RPC and HTML documentation server.
+
+    Adds the ability to serve server documentation to the capabilities
+    of SimpleXMLRPCServer.
+    """
+
+    def __init__(self, addr, requestHandler=DocXMLRPCRequestHandler,
+                 logRequests=1, allow_none=False, encoding=None,
+                 bind_and_activate=True):
+        SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests,
+                                    allow_none, encoding, bind_and_activate)
+        XMLRPCDocGenerator.__init__(self)
+
+class DocCGIXMLRPCRequestHandler(   CGIXMLRPCRequestHandler,
+                                    XMLRPCDocGenerator):
+    """Handler for XML-RPC data and documentation requests passed through
+    CGI"""
+
+    def handle_get(self):
+        """Handles the HTTP GET request.
+
+        Interpret all HTTP GET requests as requests for server
+        documentation.
+        """
+
+        response = self.generate_html_documentation()
+
+        print('Content-Type: text/html')
+        print('Content-Length: %d' % len(response))
+        print()
+        sys.stdout.write(response)
+
+    def __init__(self):
+        CGIXMLRPCRequestHandler.__init__(self)
+        XMLRPCDocGenerator.__init__(self)
+
+
 if __name__ == '__main__':
     print('Running XML-RPC server on port 8000')
     server = SimpleXMLRPCServer(("localhost", 8000))
index f8b7ee03648a9b28b3d662050bfc6131edea428e..88bd8899680c0d22e91f4e864f32b93d53aa1410 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -56,6 +56,17 @@ Extension Modules
 Library
 -------
 
+- The ``xmlrpc`` package was created; it contains the old
+  ``xmlrpclib`` module as ``xmlrpc.client`` and the content of
+  the old ``SimpleXMLRPCServer`` and ``DocXMLRPCServer`` modules
+  as ``xmlrpc.server``.  
+
+- The ``dbm`` package was created, containing the old modules
+  ``anydbm`` and ``whichdb`` in its ``__init__.py``, and having
+  ``dbm.gnu`` (was ``gdbm``), ``dbm.bsd`` (was ``dbhash``),
+  ``dbm.ndbm`` (was ``dbm``) and ``dbm.dumb`` (was ``dumbdbm``)
+  as submodules.
+
 - The ``repr`` module has been renamed to ``reprlib``.
 
 - The ``statvfs`` module has been removed.
index c959de5282b44bb2e3f3d28aa174660d9bca9bf1..ed7c98a04ded01840918415e68da72401986cbfc 100644 (file)
@@ -1952,7 +1952,8 @@ xdrlib           Implements (a subset of) Sun XDR (eXternal Data
 xmllib           A parser for XML, using the derived class as static DTD.
 xml.dom          Classes for processing XML using the Document Object Model.
 xml.sax          Classes for processing XML using the SAX API.
-xmlrpclib        Support for remote procedure calls using XML.
+xmlrpc.client    Support for remote procedure calls using XML.
+xmlrpc.server    Create XMLRPC servers.
 zipfile          Read & write PK zipped files.