mirror of
https://github.com/python/cpython.git
synced 2024-11-25 02:44:06 +08:00
b76922a7be
svn+ssh://pythondev@svn.python.org/python/trunk ........ r59455 | guido.van.rossum | 2007-12-10 21:42:53 +0100 (Mon, 10 Dec 2007) | 2 lines Remove a 2.2-ism. ........ r59459 | christian.heimes | 2007-12-10 23:28:56 +0100 (Mon, 10 Dec 2007) | 4 lines Backport of r59456:59458 from py3k to trunk Issue #1580: New free format floating point representation based on "Floating-Point Printer Sample Code", by Robert G. Burger. For example repr(11./5) now returns '2.2' instead of '2.2000000000000002'. Thanks to noam for the patch! I had to modify doubledigits.c slightly to support X64 and IA64 machines on Windows. I also added the new file to the three project files. ........ r59460 | guido.van.rossum | 2007-12-11 00:00:12 +0100 (Tue, 11 Dec 2007) | 4 lines Patch #1643738 by Ulisses Furquim -- make the is_tripped variable in signalmodule.c more robust. Includes Martin von Loewis's suggestion to set is_tripped after .tripped. ........ r59463 | kurt.kaiser | 2007-12-11 01:04:57 +0100 (Tue, 11 Dec 2007) | 2 lines format_paragraph_event wasn't returning 'break' ........ r59464 | christian.heimes | 2007-12-11 01:54:34 +0100 (Tue, 11 Dec 2007) | 3 lines The new float repr causes too much trouble and pain. I'm disabling the feature until we have sorted out the issues on all machines. 64bit machines seem to have issues and Guido has reported even worse. Guido: It's pretty bad actually -- repr(1e5) comes out as '1.0'... Ditto for repr(1eN) for most N... Both in 2.6 and in 3.0... ........
284 lines
10 KiB
Python
284 lines
10 KiB
Python
"""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 expressions 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/peps/pep-%04d.html' % 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)
|