Start packaging the bz2 python module as it is needed for building Qt5
[profile/ivi/python.git] / Lib / DocXMLRPCServer.py
1 """Self documenting XML-RPC Server.
2
3 This module can be used to create XML-RPC servers that
4 serve pydoc-style documentation in response to HTTP
5 GET requests. This documentation is dynamically generated
6 based on the functions and methods registered with the
7 server.
8
9 This module is built upon the pydoc and SimpleXMLRPCServer
10 modules.
11 """
12
13 import pydoc
14 import inspect
15 import re
16 import sys
17
18 from SimpleXMLRPCServer import (SimpleXMLRPCServer,
19             SimpleXMLRPCRequestHandler,
20             CGIXMLRPCRequestHandler,
21             resolve_dotted_attribute)
22
23 class ServerHTMLDoc(pydoc.HTMLDoc):
24     """Class used to generate pydoc HTML document for a server"""
25
26     def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
27         """Mark up some plain text, given a context of symbols to look for.
28         Each context dictionary maps object names to anchor names."""
29         escape = escape or self.escape
30         results = []
31         here = 0
32
33         # XXX Note that this regular expression does not allow for the
34         # hyperlinking of arbitrary strings being used as method
35         # names. Only methods with names consisting of word characters
36         # and '.'s are hyperlinked.
37         pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
38                                 r'RFC[- ]?(\d+)|'
39                                 r'PEP[- ]?(\d+)|'
40                                 r'(self\.)?((?:\w|\.)+))\b')
41         while 1:
42             match = pattern.search(text, here)
43             if not match: break
44             start, end = match.span()
45             results.append(escape(text[here:start]))
46
47             all, scheme, rfc, pep, selfdot, name = match.groups()
48             if scheme:
49                 url = escape(all).replace('"', '"')
50                 results.append('<a href="%s">%s</a>' % (url, url))
51             elif rfc:
52                 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
53                 results.append('<a href="%s">%s</a>' % (url, escape(all)))
54             elif pep:
55                 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
56                 results.append('<a href="%s">%s</a>' % (url, escape(all)))
57             elif text[end:end+1] == '(':
58                 results.append(self.namelink(name, methods, funcs, classes))
59             elif selfdot:
60                 results.append('self.<strong>%s</strong>' % name)
61             else:
62                 results.append(self.namelink(name, classes))
63             here = end
64         results.append(escape(text[here:]))
65         return ''.join(results)
66
67     def docroutine(self, object, name, mod=None,
68                    funcs={}, classes={}, methods={}, cl=None):
69         """Produce HTML documentation for a function or method object."""
70
71         anchor = (cl and cl.__name__ or '') + '-' + name
72         note = ''
73
74         title = '<a name="%s"><strong>%s</strong></a>' % (
75             self.escape(anchor), self.escape(name))
76
77         if inspect.ismethod(object):
78             args, varargs, varkw, defaults = inspect.getargspec(object.im_func)
79             # exclude the argument bound to the instance, it will be
80             # confusing to the non-Python user
81             argspec = inspect.formatargspec (
82                     args[1:],
83                     varargs,
84                     varkw,
85                     defaults,
86                     formatvalue=self.formatvalue
87                 )
88         elif inspect.isfunction(object):
89             args, varargs, varkw, defaults = inspect.getargspec(object)
90             argspec = inspect.formatargspec(
91                 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
92         else:
93             argspec = '(...)'
94
95         if isinstance(object, tuple):
96             argspec = object[0] or argspec
97             docstring = object[1] or ""
98         else:
99             docstring = pydoc.getdoc(object)
100
101         decl = title + argspec + (note and self.grey(
102                '<font face="helvetica, arial">%s</font>' % note))
103
104         doc = self.markup(
105             docstring, self.preformat, funcs, classes, methods)
106         doc = doc and '<dd><tt>%s</tt></dd>' % doc
107         return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
108
109     def docserver(self, server_name, package_documentation, methods):
110         """Produce HTML documentation for an XML-RPC server."""
111
112         fdict = {}
113         for key, value in methods.items():
114             fdict[key] = '#-' + key
115             fdict[value] = fdict[key]
116
117         server_name = self.escape(server_name)
118         head = '<big><big><strong>%s</strong></big></big>' % server_name
119         result = self.heading(head, '#ffffff', '#7799ee')
120
121         doc = self.markup(package_documentation, self.preformat, fdict)
122         doc = doc and '<tt>%s</tt>' % doc
123         result = result + '<p>%s</p>\n' % doc
124
125         contents = []
126         method_items = sorted(methods.items())
127         for key, value in method_items:
128             contents.append(self.docroutine(value, key, funcs=fdict))
129         result = result + self.bigsection(
130             'Methods', '#ffffff', '#eeaa77', pydoc.join(contents))
131
132         return result
133
134 class XMLRPCDocGenerator:
135     """Generates documentation for an XML-RPC server.
136
137     This class is designed as mix-in and should not
138     be constructed directly.
139     """
140
141     def __init__(self):
142         # setup variables used for HTML documentation
143         self.server_name = 'XML-RPC Server Documentation'
144         self.server_documentation = \
145             "This server exports the following methods through the XML-RPC "\
146             "protocol."
147         self.server_title = 'XML-RPC Server Documentation'
148
149     def set_server_title(self, server_title):
150         """Set the HTML title of the generated server documentation"""
151
152         self.server_title = server_title
153
154     def set_server_name(self, server_name):
155         """Set the name of the generated HTML server documentation"""
156
157         self.server_name = server_name
158
159     def set_server_documentation(self, server_documentation):
160         """Set the documentation string for the entire server."""
161
162         self.server_documentation = server_documentation
163
164     def generate_html_documentation(self):
165         """generate_html_documentation() => html documentation for the server
166
167         Generates HTML documentation for the server using introspection for
168         installed functions and instances that do not implement the
169         _dispatch method. Alternatively, instances can choose to implement
170         the _get_method_argstring(method_name) method to provide the
171         argument string used in the documentation and the
172         _methodHelp(method_name) method to provide the help text used
173         in the documentation."""
174
175         methods = {}
176
177         for method_name in self.system_listMethods():
178             if method_name in self.funcs:
179                 method = self.funcs[method_name]
180             elif self.instance is not None:
181                 method_info = [None, None] # argspec, documentation
182                 if hasattr(self.instance, '_get_method_argstring'):
183                     method_info[0] = self.instance._get_method_argstring(method_name)
184                 if hasattr(self.instance, '_methodHelp'):
185                     method_info[1] = self.instance._methodHelp(method_name)
186
187                 method_info = tuple(method_info)
188                 if method_info != (None, None):
189                     method = method_info
190                 elif not hasattr(self.instance, '_dispatch'):
191                     try:
192                         method = resolve_dotted_attribute(
193                                     self.instance,
194                                     method_name
195                                     )
196                     except AttributeError:
197                         method = method_info
198                 else:
199                     method = method_info
200             else:
201                 assert 0, "Could not find method in self.functions and no "\
202                           "instance installed"
203
204             methods[method_name] = method
205
206         documenter = ServerHTMLDoc()
207         documentation = documenter.docserver(
208                                 self.server_name,
209                                 self.server_documentation,
210                                 methods
211                             )
212
213         return documenter.page(self.server_title, documentation)
214
215 class DocXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
216     """XML-RPC and documentation request handler class.
217
218     Handles all HTTP POST requests and attempts to decode them as
219     XML-RPC requests.
220
221     Handles all HTTP GET requests and interprets them as requests
222     for documentation.
223     """
224
225     def do_GET(self):
226         """Handles the HTTP GET request.
227
228         Interpret all HTTP GET requests as requests for server
229         documentation.
230         """
231         # Check that the path is legal
232         if not self.is_rpc_path_valid():
233             self.report_404()
234             return
235
236         response = self.server.generate_html_documentation()
237         self.send_response(200)
238         self.send_header("Content-type", "text/html")
239         self.send_header("Content-length", str(len(response)))
240         self.end_headers()
241         self.wfile.write(response)
242
243 class DocXMLRPCServer(  SimpleXMLRPCServer,
244                         XMLRPCDocGenerator):
245     """XML-RPC and HTML documentation server.
246
247     Adds the ability to serve server documentation to the capabilities
248     of SimpleXMLRPCServer.
249     """
250
251     def __init__(self, addr, requestHandler=DocXMLRPCRequestHandler,
252                  logRequests=1, allow_none=False, encoding=None,
253                  bind_and_activate=True):
254         SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests,
255                                     allow_none, encoding, bind_and_activate)
256         XMLRPCDocGenerator.__init__(self)
257
258 class DocCGIXMLRPCRequestHandler(   CGIXMLRPCRequestHandler,
259                                     XMLRPCDocGenerator):
260     """Handler for XML-RPC data and documentation requests passed through
261     CGI"""
262
263     def handle_get(self):
264         """Handles the HTTP GET request.
265
266         Interpret all HTTP GET requests as requests for server
267         documentation.
268         """
269
270         response = self.generate_html_documentation()
271
272         print 'Content-Type: text/html'
273         print 'Content-Length: %d' % len(response)
274         print
275         sys.stdout.write(response)
276
277     def __init__(self):
278         CGIXMLRPCRequestHandler.__init__(self)
279         XMLRPCDocGenerator.__init__(self)