mirror of https://github.com/python/cpython
Create xmlrpc package. Issue #2886.
This commit is contained in:
parent
7f986acb01
commit
38eceaaf0c
|
@ -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.
|
|
||||||
|
|
|
@ -42,6 +42,5 @@ is currently supported on most popular platforms. Here is an overview:
|
||||||
cgihttpserver.rst
|
cgihttpserver.rst
|
||||||
cookielib.rst
|
cookielib.rst
|
||||||
cookie.rst
|
cookie.rst
|
||||||
xmlrpclib.rst
|
xmlrpc.client.rst
|
||||||
simplexmlrpcserver.rst
|
xmlrpc.server.rst
|
||||||
docxmlrpcserver.rst
|
|
||||||
|
|
|
@ -23,4 +23,5 @@ The list of modules described in this chapter is:
|
||||||
shelve.rst
|
shelve.rst
|
||||||
marshal.rst
|
marshal.rst
|
||||||
dbm.rst
|
dbm.rst
|
||||||
|
bsddb.rst
|
||||||
sqlite3.rst
|
sqlite3.rst
|
||||||
|
|
|
@ -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.
|
:synopsis: XML-RPC client access.
|
||||||
.. moduleauthor:: Fredrik Lundh <fredrik@pythonware.com>
|
.. moduleauthor:: Fredrik Lundh <fredrik@pythonware.com>
|
||||||
.. sectionauthor:: Eric S. Raymond <esr@snark.thyrsus.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
|
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.
|
: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
|
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.
|
instances of subclasses of builtin types.
|
||||||
|
|
||||||
When passing strings, characters special to XML such as ``<``, ``>``, and ``&``
|
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.
|
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::
|
A working example follows. The server code::
|
||||||
|
|
||||||
import xmlrpclib
|
from xmlrpc.server import SimpleXMLRPCServer
|
||||||
from SimpleXMLRPCServer import SimpleXMLRPCServer
|
|
||||||
|
|
||||||
def is_even(n):
|
def is_even(n):
|
||||||
return n%2 == 0
|
return n%2 == 0
|
||||||
|
@ -202,9 +183,9 @@ A working example follows. The server code::
|
||||||
|
|
||||||
The client code for the preceding server::
|
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("3 is even: %s" % str(proxy.is_even(3)))
|
||||||
print("100 is even: %s" % str(proxy.is_even(100)))
|
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::
|
A working example follows. The server code::
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from SimpleXMLRPCServer import SimpleXMLRPCServer
|
from xmlrpc.server import SimpleXMLRPCServer
|
||||||
import xmlrpclib
|
import xmlrpc.client
|
||||||
|
|
||||||
def today():
|
def today():
|
||||||
today = datetime.datetime.today()
|
today = datetime.datetime.today()
|
||||||
return xmlrpclib.DateTime(today)
|
return xmlrpc.client.DateTime(today)
|
||||||
|
|
||||||
server = SimpleXMLRPCServer(("localhost", 8000))
|
server = SimpleXMLRPCServer(("localhost", 8000))
|
||||||
print("Listening on port 8000...")
|
print("Listening on port 8000...")
|
||||||
|
@ -249,10 +230,10 @@ A working example follows. The server code::
|
||||||
|
|
||||||
The client code for the preceding server::
|
The client code for the preceding server::
|
||||||
|
|
||||||
import xmlrpclib
|
import xmlrpc.client
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
|
proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
|
||||||
|
|
||||||
today = proxy.today()
|
today = proxy.today()
|
||||||
# convert the ISO8601 string to a datetime object
|
# 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
|
Example usage of the binary objects. We're going to transfer an image over
|
||||||
XMLRPC::
|
XMLRPC::
|
||||||
|
|
||||||
from SimpleXMLRPCServer import SimpleXMLRPCServer
|
from xmlrpc.server import SimpleXMLRPCServer
|
||||||
import xmlrpclib
|
import xmlrpc.client
|
||||||
|
|
||||||
def python_logo():
|
def python_logo():
|
||||||
handle = open("python_logo.jpg")
|
handle = open("python_logo.jpg")
|
||||||
return xmlrpclib.Binary(handle.read())
|
return xmlrpc.client.Binary(handle.read())
|
||||||
handle.close()
|
handle.close()
|
||||||
|
|
||||||
server = SimpleXMLRPCServer(("localhost", 8000))
|
server = SimpleXMLRPCServer(("localhost", 8000))
|
||||||
|
@ -314,9 +295,9 @@ XMLRPC::
|
||||||
|
|
||||||
The client gets the image and saves it to a file::
|
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 = open("fetched_python_logo.jpg", "w")
|
||||||
handle.write(proxy.python_logo().data)
|
handle.write(proxy.python_logo().data)
|
||||||
handle.close()
|
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
|
In the following example we're going to intentionally cause a :exc:`Fault` by
|
||||||
returning a complex type object. The server code::
|
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
|
# A marshalling error is going to occur because we're returning a
|
||||||
# complex number
|
# complex number
|
||||||
|
@ -357,12 +338,12 @@ returning a complex type object. The server code::
|
||||||
|
|
||||||
The client code for the preceding server::
|
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:
|
try:
|
||||||
proxy.add(2, 5)
|
proxy.add(2, 5)
|
||||||
except xmlrpclib.Fault, err:
|
except xmlrpc.client.Fault, err:
|
||||||
print("A fault occured")
|
print("A fault occured")
|
||||||
print("Fault code: %d" % err.faultCode)
|
print("Fault code: %d" % err.faultCode)
|
||||||
print("Fault string: %s" % err.faultString)
|
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`
|
In the following example we're going to intentionally cause a :exc:`ProtocolError`
|
||||||
by providing an invalid URI::
|
by providing an invalid URI::
|
||||||
|
|
||||||
import xmlrpclib
|
import xmlrpc.client
|
||||||
|
|
||||||
# create a ServerProxy with an invalid URI
|
# create a ServerProxy with an invalid URI
|
||||||
proxy = xmlrpclib.ServerProxy("http://invalidaddress/")
|
proxy = xmlrpc.client.ServerProxy("http://invalidaddress/")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
proxy.some_method()
|
proxy.some_method()
|
||||||
except xmlrpclib.ProtocolError, err:
|
except xmlrpc.client.ProtocolError, err:
|
||||||
print("A protocol error occured")
|
print("A protocol error occured")
|
||||||
print("URL: %s" % err.url)
|
print("URL: %s" % err.url)
|
||||||
print("HTTP/HTTPS headers: %s" % err.headers)
|
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 ::
|
A usage example of this class follows. The server code ::
|
||||||
|
|
||||||
from SimpleXMLRPCServer import SimpleXMLRPCServer
|
from xmlrpc.server import SimpleXMLRPCServer
|
||||||
|
|
||||||
def add(x,y):
|
def add(x,y):
|
||||||
return 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::
|
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/")
|
||||||
multicall = xmlrpclib.MultiCall(proxy)
|
multicall = xmlrpc.client.MultiCall(proxy)
|
||||||
multicall.add(7,3)
|
multicall.add(7,3)
|
||||||
multicall.subtract(7,3)
|
multicall.subtract(7,3)
|
||||||
multicall.multiply(7,3)
|
multicall.multiply(7,3)
|
||||||
|
@ -477,13 +458,6 @@ The client code for the preceding server::
|
||||||
Convenience Functions
|
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]]]])
|
.. function:: dumps(params[, methodname[, methodresponse[, encoding[, allow_none]]]])
|
||||||
|
|
||||||
Convert *params* into an XML-RPC request. or into a response if *methodresponse*
|
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)
|
# 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://localhost:8000") # local server
|
||||||
server = ServerProxy("http://betty.userland.com")
|
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):
|
def set_proxy(self, proxy):
|
||||||
self.proxy = proxy
|
self.proxy = proxy
|
||||||
def make_connection(self, host):
|
def make_connection(self, host):
|
||||||
|
@ -548,7 +522,7 @@ transport. The following example shows how:
|
||||||
|
|
||||||
p = ProxiedTransport()
|
p = ProxiedTransport()
|
||||||
p.set_proxy('proxy-server:8080')
|
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())
|
print(server.currentTime.getCurrentTime())
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
|
:mod:`xmlrpc.server` --- Basic XML-RPC servers
|
||||||
|
==============================================
|
||||||
|
|
||||||
:mod:`SimpleXMLRPCServer` --- Basic XML-RPC server
|
.. module:: xmlrpc.server
|
||||||
==================================================
|
:synopsis: Basic XML-RPC server implementations.
|
||||||
|
|
||||||
.. module:: SimpleXMLRPCServer
|
|
||||||
:synopsis: Basic XML-RPC server implementation.
|
|
||||||
.. moduleauthor:: Brian Quinlan <brianq@activestate.com>
|
.. moduleauthor:: Brian Quinlan <brianq@activestate.com>
|
||||||
.. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
|
.. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
|
||||||
|
|
||||||
|
|
||||||
The :mod:`SimpleXMLRPCServer` module provides a basic server framework for
|
The :mod:`xmlrpc.server` module provides a basic server framework for XML-RPC
|
||||||
XML-RPC servers written in Python. Servers can either be free standing, using
|
servers written in Python. Servers can either be free standing, using
|
||||||
:class:`SimpleXMLRPCServer`, or embedded in a CGI environment, using
|
:class:`SimpleXMLRPCServer`, or embedded in a CGI environment, using
|
||||||
:class:`CGIXMLRPCRequestHandler`.
|
: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*
|
are passed to the :class:`socketserver.TCPServer` constructor. If *logRequests*
|
||||||
is true (the default), requests will be logged; setting this parameter to false
|
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
|
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
|
from the server. The *bind_and_activate* parameter controls whether
|
||||||
:meth:`server_bind` and :meth:`server_activate` are called immediately by the
|
: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
|
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]])
|
.. class:: CGIXMLRPCRequestHandler([allow_none[, encoding]])
|
||||||
|
|
||||||
Create a new instance to handle XML-RPC requests in a CGI environment. The
|
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
|
*allow_none* and *encoding* parameters are passed on to :mod:`xmlrpc.client`
|
||||||
control the XML-RPC responses that will be returned from the server.
|
and control the XML-RPC responses that will be returned from the server.
|
||||||
|
|
||||||
|
|
||||||
.. class:: SimpleXMLRPCRequestHandler()
|
.. class:: SimpleXMLRPCRequestHandler()
|
||||||
|
@ -115,8 +114,8 @@ SimpleXMLRPCServer Example
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Server code::
|
Server code::
|
||||||
|
|
||||||
from SimpleXMLRPCServer import SimpleXMLRPCServer
|
from xmlrpc.server import SimpleXMLRPCServer
|
||||||
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
|
from xmlrpc.server import SimpleXMLRPCRequestHandler
|
||||||
|
|
||||||
# Restrict to a particular path.
|
# Restrict to a particular path.
|
||||||
class RequestHandler(SimpleXMLRPCRequestHandler):
|
class RequestHandler(SimpleXMLRPCRequestHandler):
|
||||||
|
@ -150,9 +149,9 @@ Server code::
|
||||||
The following client code will call the methods made available by the preceding
|
The following client code will call the methods made available by the preceding
|
||||||
server::
|
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.pow(2,3)) # Returns 2**3 = 8
|
||||||
print(s.add(2,3)) # Returns 5
|
print(s.add(2,3)) # Returns 5
|
||||||
print(s.mul(5,2)) # Returns 5*2 = 10
|
print(s.mul(5,2)) # Returns 5*2 = 10
|
||||||
|
@ -220,3 +219,89 @@ Example::
|
||||||
handler.register_instance(MyFuncs())
|
handler.register_instance(MyFuncs())
|
||||||
handler.handle_request()
|
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.
|
|
@ -570,7 +570,7 @@ The :mod:`uu` module contains the following notice::
|
||||||
XML Remote Procedure Calls
|
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
|
The XML-RPC client interface is
|
||||||
|
|
||||||
|
|
|
@ -294,7 +294,7 @@ Batteries Included
|
||||||
Python has a "batteries included" philosophy. This is best seen through the
|
Python has a "batteries included" philosophy. This is best seen through the
|
||||||
sophisticated and robust capabilities of its larger packages. For example:
|
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
|
remote procedure calls into an almost trivial task. Despite the modules
|
||||||
names, no direct knowledge or handling of XML is needed.
|
names, no direct knowledge or handling of XML is needed.
|
||||||
|
|
||||||
|
|
|
@ -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('"', '"')
|
|
||||||
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)
|
|
|
@ -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()
|
|
|
@ -1,10 +1,9 @@
|
||||||
from DocXMLRPCServer import DocXMLRPCServer
|
from xmlrpc.server import DocXMLRPCServer
|
||||||
import httplib
|
import httplib
|
||||||
from test import support
|
from test import support
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
import xmlrpclib
|
|
||||||
|
|
||||||
PORT = None
|
PORT = None
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@ import datetime
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
import xmlrpclib
|
import xmlrpc.client as xmlrpclib
|
||||||
import SimpleXMLRPCServer
|
import xmlrpc.server
|
||||||
import threading
|
import threading
|
||||||
import mimetools
|
import mimetools
|
||||||
import httplib
|
import httplib
|
||||||
|
@ -160,9 +160,9 @@ class FaultTestCase(unittest.TestCase):
|
||||||
# this will raise AttirebuteError because code don't want us to use
|
# this will raise AttirebuteError because code don't want us to use
|
||||||
# private methods
|
# private methods
|
||||||
self.assertRaises(AttributeError,
|
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):
|
class DateTimeTestCase(unittest.TestCase):
|
||||||
def test_default(self):
|
def test_default(self):
|
||||||
|
@ -249,7 +249,7 @@ def http_server(evt, numrequests):
|
||||||
'''This is my function'''
|
'''This is my function'''
|
||||||
return True
|
return True
|
||||||
|
|
||||||
class MyXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
|
class MyXMLRPCServer(xmlrpc.server.SimpleXMLRPCServer):
|
||||||
def get_request(self):
|
def get_request(self):
|
||||||
# Ensure the socket is always non-blocking. On Linux, socket
|
# Ensure the socket is always non-blocking. On Linux, socket
|
||||||
# attributes are not inherited like they are on *BSD and Windows.
|
# attributes are not inherited like they are on *BSD and Windows.
|
||||||
|
@ -306,7 +306,7 @@ def is_unavailable_exception(e):
|
||||||
class SimpleServerTestCase(unittest.TestCase):
|
class SimpleServerTestCase(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# enable traceback reporting
|
# enable traceback reporting
|
||||||
SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
|
xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = True
|
||||||
|
|
||||||
self.evt = threading.Event()
|
self.evt = threading.Event()
|
||||||
# start server thread to handle requests
|
# start server thread to handle requests
|
||||||
|
@ -326,7 +326,7 @@ class SimpleServerTestCase(unittest.TestCase):
|
||||||
raise RuntimeError("timeout reached, test has failed")
|
raise RuntimeError("timeout reached, test has failed")
|
||||||
|
|
||||||
# disable traceback reporting
|
# disable traceback reporting
|
||||||
SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
|
xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = False
|
||||||
|
|
||||||
def test_simple1(self):
|
def test_simple1(self):
|
||||||
try:
|
try:
|
||||||
|
@ -443,9 +443,9 @@ class SimpleServerTestCase(unittest.TestCase):
|
||||||
def test_dotted_attribute(self):
|
def test_dotted_attribute(self):
|
||||||
# Raises an AttributeError because private methods are not allowed.
|
# Raises an AttributeError because private methods are not allowed.
|
||||||
self.assertRaises(AttributeError,
|
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.
|
# Get the test to run faster by sending a request with test_simple1.
|
||||||
# This avoids waiting for the socket timeout.
|
# This avoids waiting for the socket timeout.
|
||||||
self.test_simple1()
|
self.test_simple1()
|
||||||
|
@ -475,17 +475,17 @@ class FailingServerTestCase(unittest.TestCase):
|
||||||
# wait on the server thread to terminate
|
# wait on the server thread to terminate
|
||||||
self.evt.wait()
|
self.evt.wait()
|
||||||
# reset flag
|
# reset flag
|
||||||
SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = False
|
xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = False
|
||||||
# reset message class
|
# reset message class
|
||||||
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message
|
xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = mimetools.Message
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
# check that flag is false by default
|
# check that flag is false by default
|
||||||
flagval = SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header
|
flagval = xmlrpc.server.SimpleXMLRPCServer._send_traceback_header
|
||||||
self.assertEqual(flagval, False)
|
self.assertEqual(flagval, False)
|
||||||
|
|
||||||
# enable traceback reporting
|
# 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
|
# test a call that shouldn't fail just as a smoke test
|
||||||
try:
|
try:
|
||||||
|
@ -499,7 +499,7 @@ class FailingServerTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def test_fail_no_info(self):
|
def test_fail_no_info(self):
|
||||||
# use the broken message class
|
# use the broken message class
|
||||||
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
|
xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
|
p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
|
||||||
|
@ -515,11 +515,11 @@ class FailingServerTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def test_fail_with_info(self):
|
def test_fail_with_info(self):
|
||||||
# use the broken message class
|
# use the broken message class
|
||||||
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
|
xmlrpc.server.SimpleXMLRPCRequestHandler.MessageClass = FailingMessageClass
|
||||||
|
|
||||||
# Check that errors in the server send back exception/traceback
|
# Check that errors in the server send back exception/traceback
|
||||||
# info when flag is set
|
# info when flag is set
|
||||||
SimpleXMLRPCServer.SimpleXMLRPCServer._send_traceback_header = True
|
xmlrpc.server.SimpleXMLRPCServer._send_traceback_header = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
|
p = xmlrpclib.ServerProxy('http://localhost:%d' % PORT)
|
||||||
|
@ -536,7 +536,7 @@ class FailingServerTestCase(unittest.TestCase):
|
||||||
|
|
||||||
class CGIHandlerTestCase(unittest.TestCase):
|
class CGIHandlerTestCase(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.cgi = SimpleXMLRPCServer.CGIXMLRPCRequestHandler()
|
self.cgi = xmlrpc.server.CGIXMLRPCRequestHandler()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.cgi = None
|
self.cgi = None
|
||||||
|
|
|
@ -6,7 +6,7 @@ import sys
|
||||||
import unittest
|
import unittest
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
import xmlrpclib
|
import xmlrpclib.client as xmlrpclib
|
||||||
|
|
||||||
class CurrentTimeTest(unittest.TestCase):
|
class CurrentTimeTest(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
# This directory is a Python package.
|
|
@ -108,7 +108,6 @@ Exported classes:
|
||||||
ServerProxy Represents a logical connection to an XML-RPC server
|
ServerProxy Represents a logical connection to an XML-RPC server
|
||||||
|
|
||||||
MultiCall Executor of boxcared xmlrpc requests
|
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
|
DateTime dateTime wrapper for an ISO 8601 string or time tuple or
|
||||||
localtime integer value to generate a "dateTime.iso8601"
|
localtime integer value to generate a "dateTime.iso8601"
|
||||||
XML-RPC value
|
XML-RPC value
|
||||||
|
@ -127,7 +126,6 @@ Exported constants:
|
||||||
|
|
||||||
Exported functions:
|
Exported functions:
|
||||||
|
|
||||||
boolean Convert any Python value to an XML-RPC boolean
|
|
||||||
getparser Create instance of the fastest available parser & attach
|
getparser Create instance of the fastest available parser & attach
|
||||||
to an unmarshalling object
|
to an unmarshalling object
|
||||||
dumps Convert an argument tuple or a Fault instance to an XML-RPC
|
dumps Convert an argument tuple or a Fault instance to an XML-RPC
|
||||||
|
@ -147,11 +145,6 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
datetime = None
|
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):
|
def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
|
||||||
# decode non-ascii string (if possible)
|
# decode non-ascii string (if possible)
|
||||||
if encoding and is8bit(data):
|
if encoding and is8bit(data):
|
||||||
|
@ -265,12 +258,7 @@ class Fault(Error):
|
||||||
# Special values
|
# Special values
|
||||||
|
|
||||||
##
|
##
|
||||||
# Wrapper for XML-RPC boolean values. Use the xmlrpclib.True and
|
# Backwards compatibility
|
||||||
# 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.
|
|
||||||
|
|
||||||
boolean = Boolean = bool
|
boolean = Boolean = bool
|
||||||
|
|
||||||
|
@ -451,26 +439,10 @@ def _binary(data):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
WRAPPERS = (DateTime, Binary)
|
WRAPPERS = (DateTime, Binary)
|
||||||
if not _bool_is_builtin:
|
|
||||||
WRAPPERS = WRAPPERS + (Boolean,)
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# XML parsers
|
# 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
|
# the SGMLOP parser is about 15x faster than Python's builtin
|
||||||
# XML parser. SGMLOP sources can be downloaded from:
|
# XML parser. SGMLOP sources can be downloaded from:
|
||||||
|
@ -640,12 +612,11 @@ class Marshaller:
|
||||||
write("</int></value>\n")
|
write("</int></value>\n")
|
||||||
#dispatch[int] = dump_int
|
#dispatch[int] = dump_int
|
||||||
|
|
||||||
if _bool_is_builtin:
|
def dump_bool(self, value, write):
|
||||||
def dump_bool(self, value, write):
|
write("<value><boolean>")
|
||||||
write("<value><boolean>")
|
write(value and "1" or "0")
|
||||||
write(value and "1" or "0")
|
write("</boolean></value>\n")
|
||||||
write("</boolean></value>\n")
|
dispatch[bool] = dump_bool
|
||||||
dispatch[bool] = dump_bool
|
|
||||||
|
|
||||||
def dump_long(self, value, write):
|
def dump_long(self, value, write):
|
||||||
if value > MAXINT or value < MININT:
|
if value > MAXINT or value < MININT:
|
||||||
|
@ -968,6 +939,8 @@ class MultiCall:
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
# convenience functions
|
# convenience functions
|
||||||
|
|
||||||
|
FastMarshaller = FastParser = FastUnmarshaller = None
|
||||||
|
|
||||||
##
|
##
|
||||||
# Create a parser object, and connect it to an unmarshalling instance.
|
# Create a parser object, and connect it to an unmarshalling instance.
|
||||||
# This function picks the fastest available XML parser.
|
# This function picks the fastest available XML parser.
|
|
@ -1,4 +1,4 @@
|
||||||
"""Simple XML-RPC Server.
|
"""XML-RPC Servers.
|
||||||
|
|
||||||
This module can be used to create simple XML-RPC servers
|
This module can be used to create simple XML-RPC servers
|
||||||
by creating a server and either installing functions, a
|
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
|
It can also be used to handle XML-RPC requests in a CGI
|
||||||
environment using CGIXMLRPCRequestHandler.
|
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:
|
A list of possible usage patterns follows:
|
||||||
|
|
||||||
1. Install functions:
|
1. Install functions:
|
||||||
|
@ -98,12 +104,14 @@ server.handle_request()
|
||||||
# Written by Brian Quinlan (brian@sweetapp.com).
|
# Written by Brian Quinlan (brian@sweetapp.com).
|
||||||
# Based on code written by Fredrik Lundh.
|
# Based on code written by Fredrik Lundh.
|
||||||
|
|
||||||
import xmlrpclib
|
from xmlrpc.client import Fault, dumps, loads
|
||||||
from xmlrpclib import Fault
|
|
||||||
import socketserver
|
import socketserver
|
||||||
import BaseHTTPServer
|
import BaseHTTPServer
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import pydoc
|
||||||
|
import inspect
|
||||||
import traceback
|
import traceback
|
||||||
try:
|
try:
|
||||||
import fcntl
|
import fcntl
|
||||||
|
@ -235,7 +243,7 @@ class SimpleXMLRPCDispatcher:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
params, method = xmlrpclib.loads(data)
|
params, method = loads(data)
|
||||||
|
|
||||||
# generate response
|
# generate response
|
||||||
if dispatch_method is not None:
|
if dispatch_method is not None:
|
||||||
|
@ -244,16 +252,16 @@ class SimpleXMLRPCDispatcher:
|
||||||
response = self._dispatch(method, params)
|
response = self._dispatch(method, params)
|
||||||
# wrap response in a singleton tuple
|
# wrap response in a singleton tuple
|
||||||
response = (response,)
|
response = (response,)
|
||||||
response = xmlrpclib.dumps(response, methodresponse=1,
|
response = dumps(response, methodresponse=1,
|
||||||
allow_none=self.allow_none, encoding=self.encoding)
|
allow_none=self.allow_none, encoding=self.encoding)
|
||||||
except Fault as fault:
|
except Fault as fault:
|
||||||
response = xmlrpclib.dumps(fault, allow_none=self.allow_none,
|
response = dumps(fault, allow_none=self.allow_none,
|
||||||
encoding=self.encoding)
|
encoding=self.encoding)
|
||||||
except:
|
except:
|
||||||
# report exception back to server
|
# report exception back to server
|
||||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||||
response = xmlrpclib.dumps(
|
response = dumps(
|
||||||
xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value)),
|
Fault(1, "%s:%s" % (exc_type, exc_value)),
|
||||||
encoding=self.encoding, allow_none=self.allow_none,
|
encoding=self.encoding, allow_none=self.allow_none,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -585,6 +593,273 @@ class CGIXMLRPCRequestHandler(SimpleXMLRPCDispatcher):
|
||||||
|
|
||||||
self.handle_xmlrpc(request_text)
|
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('"', '"')
|
||||||
|
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__':
|
if __name__ == '__main__':
|
||||||
print('Running XML-RPC server on port 8000')
|
print('Running XML-RPC server on port 8000')
|
||||||
server = SimpleXMLRPCServer(("localhost", 8000))
|
server = SimpleXMLRPCServer(("localhost", 8000))
|
11
Misc/NEWS
11
Misc/NEWS
|
@ -56,6 +56,17 @@ Extension Modules
|
||||||
Library
|
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 ``repr`` module has been renamed to ``reprlib``.
|
||||||
|
|
||||||
- The ``statvfs`` module has been removed.
|
- The ``statvfs`` module has been removed.
|
||||||
|
|
|
@ -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.
|
xmllib A parser for XML, using the derived class as static DTD.
|
||||||
xml.dom Classes for processing XML using the Document Object Model.
|
xml.dom Classes for processing XML using the Document Object Model.
|
||||||
xml.sax Classes for processing XML using the SAX API.
|
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.
|
zipfile Read & write PK zipped files.
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue