Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / tools / src / nas,5.n2.os.2 / lib / python / lib / python2.4 / DocXMLRPCServer.py
CommitLineData
86530b38
AT
1"""Self documenting XML-RPC Server.
2
3This module can be used to create XML-RPC servers that
4serve pydoc-style documentation in response to HTTP
5GET requests. This documentation is dynamically generated
6based on the functions and methods registered with the
7server.
8
9This module is built upon the pydoc and SimpleXMLRPCServer
10modules.
11"""
12
13import pydoc
14import inspect
15import types
16import re
17import sys
18
19from SimpleXMLRPCServer import (SimpleXMLRPCServer,
20 SimpleXMLRPCRequestHandler,
21 CGIXMLRPCRequestHandler,
22 resolve_dotted_attribute)
23
24class ServerHTMLDoc(pydoc.HTMLDoc):
25 """Class used to generate pydoc HTML document for a server"""
26
27 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
28 """Mark up some plain text, given a context of symbols to look for.
29 Each context dictionary maps object names to anchor names."""
30 escape = escape or self.escape
31 results = []
32 here = 0
33
34 # XXX Note that this regular expressions does not allow for the
35 # hyperlinking of arbitrary strings being used as method
36 # names. Only methods with names consisting of word characters
37 # and '.'s are hyperlinked.
38 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
39 r'RFC[- ]?(\d+)|'
40 r'PEP[- ]?(\d+)|'
41 r'(self\.)?((?:\w|\.)+))\b')
42 while 1:
43 match = pattern.search(text, here)
44 if not match: break
45 start, end = match.span()
46 results.append(escape(text[here:start]))
47
48 all, scheme, rfc, pep, selfdot, name = match.groups()
49 if scheme:
50 url = escape(all).replace('"', '"')
51 results.append('<a href="%s">%s</a>' % (url, url))
52 elif rfc:
53 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
54 results.append('<a href="%s">%s</a>' % (url, escape(all)))
55 elif pep:
56 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
57 results.append('<a href="%s">%s</a>' % (url, escape(all)))
58 elif text[end:end+1] == '(':
59 results.append(self.namelink(name, methods, funcs, classes))
60 elif selfdot:
61 results.append('self.<strong>%s</strong>' % name)
62 else:
63 results.append(self.namelink(name, classes))
64 here = end
65 results.append(escape(text[here:]))
66 return ''.join(results)
67
68 def docroutine(self, object, name=None, mod=None,
69 funcs={}, classes={}, methods={}, cl=None):
70 """Produce HTML documentation for a function or method object."""
71
72 anchor = (cl and cl.__name__ or '') + '-' + name
73 note = ''
74
75 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, 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, types.TupleType):
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 head = '<big><big><strong>%s</strong></big></big>' % server_name
118 result = self.heading(head, '#ffffff', '#7799ee')
119
120 doc = self.markup(package_documentation, self.preformat, fdict)
121 doc = doc and '<tt>%s</tt>' % doc
122 result = result + '<p>%s</p>\n' % doc
123
124 contents = []
125 method_items = methods.items()
126 method_items.sort()
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
134class 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 self.funcs.has_key(method_name):
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
215class 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
232 response = self.server.generate_html_documentation()
233 self.send_response(200)
234 self.send_header("Content-type", "text/html")
235 self.send_header("Content-length", str(len(response)))
236 self.end_headers()
237 self.wfile.write(response)
238
239 # shut down the connection
240 self.wfile.flush()
241 self.connection.shutdown(1)
242
243class 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):
253 SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests)
254 XMLRPCDocGenerator.__init__(self)
255
256class DocCGIXMLRPCRequestHandler( CGIXMLRPCRequestHandler,
257 XMLRPCDocGenerator):
258 """Handler for XML-RPC data and documentation requests passed through
259 CGI"""
260
261 def handle_get(self):
262 """Handles the HTTP GET request.
263
264 Interpret all HTTP GET requests as requests for server
265 documentation.
266 """
267
268 response = self.generate_html_documentation()
269
270 print 'Content-Type: text/html'
271 print 'Content-Length: %d' % len(response)
272 print
273 sys.stdout.write(response)
274
275 def __init__(self):
276 CGIXMLRPCRequestHandler.__init__(self)
277 XMLRPCDocGenerator.__init__(self)
278
279if __name__ == '__main__':
280 def deg_to_rad(deg):
281 """deg_to_rad(90) => 1.5707963267948966
282
283 Converts an angle in degrees to an angle in radians"""
284 import math
285 return deg * math.pi / 180
286
287 server = DocXMLRPCServer(("localhost", 8000))
288
289 server.set_server_title("Math Server")
290 server.set_server_name("Math XML-RPC Server")
291 server.set_server_documentation("""This server supports various mathematical functions.
292
293You can use it from Python as follows:
294
295>>> from xmlrpclib import ServerProxy
296>>> s = ServerProxy("http://localhost:8000")
297>>> s.deg_to_rad(90.0)
2981.5707963267948966""")
299
300 server.register_function(deg_to_rad)
301 server.register_introspection_functions()
302
303 server.serve_forever()