Create xmlrpc package. Issue #2886.

This commit is contained in:
Georg Brandl 2008-05-26 11:14:17 +00:00
parent 7f986acb01
commit 38eceaaf0c
17 changed files with 462 additions and 668 deletions

View File

@ -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.

View 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

View File

@ -23,4 +23,5 @@ The list of modules described in this chapter is:
shelve.rst
marshal.rst
dbm.rst
bsddb.rst
sqlite3.rst

View 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())

View 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.

View 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

View 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.

View File

@ -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)

View File

@ -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()

View 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

View 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

View File

@ -6,7 +6,7 @@ import sys
import unittest
from test import support
import xmlrpclib
import xmlrpclib.client as xmlrpclib
class CurrentTimeTest(unittest.TestCase):

1
Lib/xmlrpc/__init__.py Normal file
View File

@ -0,0 +1 @@
# This directory is a Python package.

View 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.

View 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))

View File

@ -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.

View 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.