ยปCore Development>Code coverage>Lib/DocXMLRPCServer.py

Python code coverage for Lib/DocXMLRPCServer.py

#countcontent
1n/a"""Self documenting XML-RPC Server.
2n/a
3n/aThis module can be used to create XML-RPC servers that
4n/aserve pydoc-style documentation in response to HTTP
5n/aGET requests. This documentation is dynamically generated
6n/abased on the functions and methods registered with the
7n/aserver.
8n/a
9n/aThis module is built upon the pydoc and SimpleXMLRPCServer
10n/amodules.
111"""
12n/a
131import pydoc
141import inspect
151import re
161import sys
17n/a
181from SimpleXMLRPCServer import (SimpleXMLRPCServer,
19n/a SimpleXMLRPCRequestHandler,
20n/a CGIXMLRPCRequestHandler,
21n/a resolve_dotted_attribute)
22n/a
232class ServerHTMLDoc(pydoc.HTMLDoc):
241 """Class used to generate pydoc HTML document for a server"""
25n/a
261 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
27n/a """Mark up some plain text, given a context of symbols to look for.
28n/a Each context dictionary maps object names to anchor names."""
2935 escape = escape or self.escape
3035 results = []
3135 here = 0
32n/a
33n/a # XXX Note that this regular expression does not allow for the
34n/a # hyperlinking of arbitrary strings being used as method
35n/a # names. Only methods with names consisting of word characters
36n/a # and '.'s are hyperlinked.
3735 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
38n/a r'RFC[- ]?(\d+)|'
39n/a r'PEP[- ]?(\d+)|'
40n/a r'(self\.)?((?:\w|\.)+))\b')
4135 while 1:
42685 match = pattern.search(text, here)
43685 if not match: break
44650 start, end = match.span()
45650 results.append(escape(text[here:start]))
46n/a
47650 all, scheme, rfc, pep, selfdot, name = match.groups()
48650 if scheme:
495 url = escape(all).replace('"', '"')
505 results.append('<a href="%s">%s</a>' % (url, url))
51645 elif rfc:
525 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
535 results.append('<a href="%s">%s</a>' % (url, escape(all)))
54640 elif pep:
555 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
565 results.append('<a href="%s">%s</a>' % (url, escape(all)))
57635 elif text[end:end+1] == '(':
5815 results.append(self.namelink(name, methods, funcs, classes))
59620 elif selfdot:
605 results.append('self.<strong>%s</strong>' % name)
61n/a else:
62615 results.append(self.namelink(name, classes))
63650 here = end
6435 results.append(escape(text[here:]))
6535 return ''.join(results)
66n/a
671 def docroutine(self, object, name, mod=None,
681 funcs={}, classes={}, methods={}, cl=None):
69n/a """Produce HTML documentation for a function or method object."""
70n/a
7130 anchor = (cl and cl.__name__ or '') + '-' + name
7230 note = ''
73n/a
7430 title = '<a name="%s"><strong>%s</strong></a>' % (
7530 self.escape(anchor), self.escape(name))
76n/a
7730 if inspect.ismethod(object):
7820 args, varargs, varkw, defaults = inspect.getargspec(object.im_func)
79n/a # exclude the argument bound to the instance, it will be
80n/a # confusing to the non-Python user
8120 argspec = inspect.formatargspec (
8220 args[1:],
8320 varargs,
8420 varkw,
8520 defaults,
8620 formatvalue=self.formatvalue
87n/a )
8810 elif inspect.isfunction(object):
8910 args, varargs, varkw, defaults = inspect.getargspec(object)
9010 argspec = inspect.formatargspec(
9110 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
92n/a else:
930 argspec = '(...)'
94n/a
9530 if isinstance(object, tuple):
960 argspec = object[0] or argspec
970 docstring = object[1] or ""
98n/a else:
9930 docstring = pydoc.getdoc(object)
100n/a
10130 decl = title + argspec + (note and self.grey(
1020 '<font face="helvetica, arial">%s</font>' % note))
103n/a
10430 doc = self.markup(
10530 docstring, self.preformat, funcs, classes, methods)
10630 doc = doc and '<dd><tt>%s</tt></dd>' % doc
10730 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
108n/a
1091 def docserver(self, server_name, package_documentation, methods):
110n/a """Produce HTML documentation for an XML-RPC server."""
111n/a
1125 fdict = {}
11335 for key, value in methods.items():
11430 fdict[key] = '#-' + key
11530 fdict[value] = fdict[key]
116n/a
1175 server_name = self.escape(server_name)
1185 head = '<big><big><strong>%s</strong></big></big>' % server_name
1195 result = self.heading(head, '#ffffff', '#7799ee')
120n/a
1215 doc = self.markup(package_documentation, self.preformat, fdict)
1225 doc = doc and '<tt>%s</tt>' % doc
1235 result = result + '<p>%s</p>\n' % doc
124n/a
1255 contents = []
1265 method_items = sorted(methods.items())
12735 for key, value in method_items:
12830 contents.append(self.docroutine(value, key, funcs=fdict))
1295 result = result + self.bigsection(
1305 'Methods', '#ffffff', '#eeaa77', pydoc.join(contents))
131n/a
1325 return result
133n/a
1342class XMLRPCDocGenerator:
135n/a """Generates documentation for an XML-RPC server.
136n/a
137n/a This class is designed as mix-in and should not
138n/a be constructed directly.
1391 """
140n/a
1411 def __init__(self):
142n/a # setup variables used for HTML documentation
1436 self.server_name = 'XML-RPC Server Documentation'
144n/a self.server_documentation = \
1456 "This server exports the following methods through the XML-RPC "\
146n/a "protocol."
1476 self.server_title = 'XML-RPC Server Documentation'
148n/a
1491 def set_server_title(self, server_title):
150n/a """Set the HTML title of the generated server documentation"""
151n/a
1526 self.server_title = server_title
153n/a
1541 def set_server_name(self, server_name):
155n/a """Set the name of the generated HTML server documentation"""
156n/a
1576 self.server_name = server_name
158n/a
1591 def set_server_documentation(self, server_documentation):
160n/a """Set the documentation string for the entire server."""
161n/a
1626 self.server_documentation = server_documentation
163n/a
1641 def generate_html_documentation(self):
165n/a """generate_html_documentation() => html documentation for the server
166n/a
167n/a Generates HTML documentation for the server using introspection for
168n/a installed functions and instances that do not implement the
169n/a _dispatch method. Alternatively, instances can choose to implement
170n/a the _get_method_argstring(method_name) method to provide the
171n/a argument string used in the documentation and the
172n/a _methodHelp(method_name) method to provide the help text used
173n/a in the documentation."""
174n/a
1755 methods = {}
176n/a
17735 for method_name in self.system_listMethods():
17830 if method_name in self.funcs:
17925 method = self.funcs[method_name]
1805 elif self.instance is not None:
1815 method_info = [None, None] # argspec, documentation
1825 if hasattr(self.instance, '_get_method_argstring'):
1830 method_info[0] = self.instance._get_method_argstring(method_name)
1845 if hasattr(self.instance, '_methodHelp'):
1850 method_info[1] = self.instance._methodHelp(method_name)
186n/a
1875 method_info = tuple(method_info)
1885 if method_info != (None, None):
1890 method = method_info
1905 elif not hasattr(self.instance, '_dispatch'):
1915 try:
1925 method = resolve_dotted_attribute(
1935 self.instance,
1945 method_name
195n/a )
1960 except AttributeError:
1970 method = method_info
198n/a else:
1990 method = method_info
200n/a else:
2010 assert 0, "Could not find method in self.functions and no "\
202n/a "instance installed"
203n/a
20430 methods[method_name] = method
205n/a
2065 documenter = ServerHTMLDoc()
2075 documentation = documenter.docserver(
2085 self.server_name,
2095 self.server_documentation,
2105 methods
211n/a )
212n/a
2135 return documenter.page(self.server_title, documentation)
214n/a
2152class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
216n/a """XML-RPC and documentation request handler class.
217n/a
218n/a Handles all HTTP POST requests and attempts to decode them as
219n/a XML-RPC requests.
220n/a
221n/a Handles all HTTP GET requests and interprets them as requests
222n/a for documentation.
2231 """
224n/a
2251 def do_GET(self):
226n/a """Handles the HTTP GET request.
227n/a
228n/a Interpret all HTTP GET requests as requests for server
229n/a documentation.
230n/a """
231n/a # Check that the path is legal
2326 if not self.is_rpc_path_valid():
2331 self.report_404()
2341 return
235n/a
2365 response = self.server.generate_html_documentation()
2375 self.send_response(200)
2385 self.send_header("Content-type", "text/html")
2395 self.send_header("Content-length", str(len(response)))
2405 self.end_headers()
2415 self.wfile.write(response)
242n/a
2432class DocXMLRPCServer( SimpleXMLRPCServer,
2441 XMLRPCDocGenerator):
245n/a """XML-RPC and HTML documentation server.
246n/a
247n/a Adds the ability to serve server documentation to the capabilities
248n/a of SimpleXMLRPCServer.
2491 """
250n/a
2511 def __init__(self, addr, requestHandler=DocXMLRPCRequestHandler,
2521 logRequests=1, allow_none=False, encoding=None,
2531 bind_and_activate=True):
2546 SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests,
2556 allow_none, encoding, bind_and_activate)
2566 XMLRPCDocGenerator.__init__(self)
257n/a
2582class DocCGIXMLRPCRequestHandler( CGIXMLRPCRequestHandler,
2591 XMLRPCDocGenerator):
260n/a """Handler for XML-RPC data and documentation requests passed through
2611 CGI"""
262n/a
2631 def handle_get(self):
264n/a """Handles the HTTP GET request.
265n/a
266n/a Interpret all HTTP GET requests as requests for server
267n/a documentation.
268n/a """
269n/a
2700 response = self.generate_html_documentation()
271n/a
2720 print 'Content-Type: text/html'
2730 print 'Content-Length: %d' % len(response)
2740 print
2750 sys.stdout.write(response)
276n/a
2771 def __init__(self):
2780 CGIXMLRPCRequestHandler.__init__(self)
2790 XMLRPCDocGenerator.__init__(self)