Merge remote-tracking branch 'origin/pycurl' into planetlab-4_0-branch
[plcapi.git] / doc / DocBook.py
1 #!/usr/bin/python
2 #
3 # Generates a DocBook section documenting all PLCAPI methods on
4 # stdout.
5 #
6 # Mark Huang <mlhuang@cs.princeton.edu>
7 # Copyright (C) 2006 The Trustees of Princeton University
8 #
9 # $Id: DocBook.py,v 1.4 2007/02/19 18:02:39 mlhuang Exp $
10 #
11
12 import xml.dom.minidom
13 from xml.dom.minidom import Element, Text
14 import codecs
15
16 from PLC.API import PLCAPI
17 from PLC.Method import *
18
19 api = PLCAPI(None)
20
21 # xml.dom.minidom.Text.writexml adds surrounding whitespace to textual
22 # data when pretty-printing. Override this behavior.
23 class TrimText(Text):
24     """text"""
25     def __init__(self, text = None):
26         self.data = unicode(text)
27
28     def writexml(self, writer, indent="", addindent="", newl=""):
29         Text.writexml(self, writer, "", "", "")
30
31 class TrimTextElement(Element):
32     """<tagName>text</tagName>"""
33     def __init__(self, tagName, text = None):
34         Element.__init__(self, tagName)
35         if text is not None:
36             self.appendChild(TrimText(text))
37
38     def writexml(self, writer, indent="", addindent="", newl=""):
39         writer.write(indent)
40         Element.writexml(self, writer, "", "", "")
41         writer.write(newl)
42
43 class simpleElement(TrimTextElement): pass
44
45 class paraElement(simpleElement):
46     """<para>text</para>"""
47     def __init__(self, text = None):
48         simpleElement.__init__(self, 'para', text)
49
50 class blockquoteElement(Element):
51     """<blockquote><para>text...</para><para>...text</para></blockquote>"""
52     def __init__(self, text = None):
53         Element.__init__(self, 'blockquote')
54         if text is not None:
55             # Split on blank lines
56             lines = [line.strip() for line in text.strip().split("\n")]
57             lines = "\n".join(lines)
58             paragraphs = lines.split("\n\n")
59
60             for paragraph in paragraphs:
61                 self.appendChild(paraElement(paragraph))
62
63 def param_type(param):
64     """Return the XML-RPC type of a parameter."""
65     if isinstance(param, Mixed) and len(param):
66         subtypes = [param_type(subparam) for subparam in param]
67         return " or ".join(subtypes)
68     elif isinstance(param, (list, tuple, set)) and len(param):
69         return "array of " + " or ".join([param_type(subparam) for subparam in param])
70     else:
71         return xmlrpc_type(python_type(param))
72
73 class paramElement(Element):
74     """An optionally named parameter."""
75     def __init__(self, name, param):
76         # <listitem>
77         Element.__init__(self, 'listitem')
78
79         description = Element('para')
80
81         if name:
82             description.appendChild(simpleElement('parameter', name))
83             description.appendChild(TrimText(": "))
84
85         description.appendChild(TrimText(param_type(param)))
86
87         if isinstance(param, (list, tuple, set)) and len(param) == 1:
88             param = param[0]
89
90         if isinstance(param, Parameter):
91             description.appendChild(TrimText(", " + param.doc))
92             param = param.type
93
94         self.appendChild(description)
95
96         if isinstance(param, dict):
97             itemizedlist = Element('itemizedlist')
98             self.appendChild(itemizedlist)
99             for name, subparam in param.iteritems():
100                 itemizedlist.appendChild(paramElement(name, subparam))
101
102         elif isinstance(param, (list, tuple, set)) and len(param):
103             itemizedlist = Element('itemizedlist')
104             self.appendChild(itemizedlist)
105             for subparam in param:
106                 itemizedlist.appendChild(paramElement(None, subparam))
107
108 for method in api.methods:
109     func = api.callable(method)
110
111     if func.status == "deprecated":
112         continue
113
114     (min_args, max_args, defaults) = func.args()
115
116     section = Element('section')
117     section.setAttribute('id', func.name)
118     section.appendChild(simpleElement('title', func.name))
119
120     prototype = "%s (%s)" % (method, ", ".join(max_args))
121     para = paraElement('Prototype:')
122     para.appendChild(blockquoteElement(prototype))
123     section.appendChild(para)
124
125     para = paraElement('Description:')
126     para.appendChild(blockquoteElement(func.__doc__))
127     section.appendChild(para)
128
129     para = paraElement('Allowed Roles:')
130     para.appendChild(blockquoteElement(", ".join(func.roles)))
131     section.appendChild(para)
132
133     section.appendChild(paraElement('Parameters:'))
134     params = Element('itemizedlist')
135     if func.accepts:
136         for name, param, default in zip(max_args, func.accepts, defaults):
137             params.appendChild(paramElement(name, param))
138     else:
139         listitem = Element('listitem')
140         listitem.appendChild(paraElement('None'))
141         params.appendChild(listitem)
142     section.appendChild(params)
143
144     section.appendChild(paraElement('Returns:'))
145     returns = Element('itemizedlist')
146     returns.appendChild(paramElement(None, func.returns))
147     section.appendChild(returns)
148
149     print section.toprettyxml(encoding = "UTF-8")