7.1-2
[plcapi.git] / doc / DocBook.py
1 #!/usr/bin/env python3
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
10 # dec 2018
11 # going for python3; xml.dom.minidom has changed a lot
12 # working around the changes in a rather quick & dirty way
13
14 import xml.dom.minidom
15 from xml.dom.minidom import Element, parseString
16
17 from PLC.Parameter import Parameter, Mixed, xmlrpc_type, python_type
18
19 # can no longer create elements out of a document
20 dom = parseString('<dummydoc/>')
21
22 def text_node(text):
23     global dom
24     return dom.createTextNode(text)
25
26 class TextElement(Element):
27     """<tagName>text</tagName>"""
28     def __init__(self, tagName, text = None):
29         Element.__init__(self, tagName)
30         if text is not None:
31             self.appendChild(text_node(text))
32
33     def writexml(self, writer, indent="", addindent="", newl=""):
34         writer.write(indent)
35         Element.writexml(self, writer, "", "", "")
36         writer.write(newl)
37
38 class simpleElement(TextElement):
39     def __init__(self, *args, **kwds):
40         super().__init__(*args, **kwds)
41
42 class paraElement(simpleElement):
43     """<para>text</para>"""
44     def __init__(self, text = None):
45         simpleElement.__init__(self, 'para', text)
46
47 class blockquoteElement(Element):
48     """<blockquote><para>text...</para><para>...text</para></blockquote>"""
49     def __init__(self, text = None):
50         Element.__init__(self, 'blockquote')
51         if text is not None:
52             # Split on blank lines
53             lines = [line.strip() for line in text.strip().split("\n")]
54             lines = "\n".join(lines)
55             paragraphs = lines.split("\n\n")
56
57             for paragraph in paragraphs:
58                 self.appendChild(paraElement(paragraph))
59
60 def param_type(param):
61     """Return the XML-RPC type of a parameter."""
62     if isinstance(param, Mixed) and len(param):
63         subtypes = [param_type(subparam) for subparam in param]
64         return " or ".join(subtypes)
65     elif isinstance(param, (list, tuple, set)) and len(param):
66         return "array of " + " or ".join([param_type(subparam) for subparam in param])
67     else:
68         return xmlrpc_type(python_type(param))
69
70 class paramElement(Element):
71     """An optionally named parameter."""
72     def __init__(self, name, param):
73         # <listitem>
74         Element.__init__(self, 'listitem')
75
76         global dom
77         description = dom.createElement('para')
78
79         if name:
80             description.appendChild(simpleElement('parameter', name))
81             description.appendChild(text_node(": "))
82
83         description.appendChild(text_node(param_type(param)))
84
85         if isinstance(param, (list, tuple, set)) and len(param) == 1:
86             param = param[0]
87
88         if isinstance(param, Parameter):
89             description.appendChild(text_node(", " + param.doc))
90             param = param.type
91
92         self.appendChild(description)
93
94         if isinstance(param, dict):
95             itemizedlist = dom.createElement('itemizedlist')
96             self.appendChild(itemizedlist)
97             for name, subparam in param.items():
98                 itemizedlist.appendChild(paramElement(name, subparam))
99
100         elif isinstance(param, (list, tuple, set)) and len(param):
101             itemizedlist = dom.createElement('itemizedlist')
102             self.appendChild(itemizedlist)
103             for subparam in param:
104                 itemizedlist.appendChild(paramElement(None, subparam))
105
106 class DocBook:
107
108     def __init__ (self, functions_list):
109         self.functions_list = functions_list
110
111     def Process (self):
112
113         global dom
114
115         for func in self.functions_list:
116             method = func.name
117
118             if func.status == "deprecated":
119                 continue
120
121             (min_args, max_args, defaults) = func.args()
122
123             # with python3 it looks like an element can't be sfa_created
124             # outside of a document
125             section = dom.createElement('section')
126             section.setAttribute('id', func.name)
127             section.appendChild(simpleElement('title', func.name))
128
129             prototype = "%s (%s)" % (method, ", ".join(max_args))
130             para = paraElement('Prototype:')
131             para.appendChild(blockquoteElement(prototype))
132             section.appendChild(para)
133
134             para = paraElement('Description:')
135             para.appendChild(blockquoteElement(func.__doc__))
136             section.appendChild(para)
137
138             para = paraElement('Allowed Roles:')
139             para.appendChild(blockquoteElement(", ".join(func.roles)))
140             section.appendChild(para)
141
142             section.appendChild(paraElement('Parameters:'))
143             params = Element('itemizedlist')
144             if func.accepts:
145                 for name, param, default in zip(max_args, func.accepts, defaults):
146                     params.appendChild(paramElement(name, param))
147             else:
148                 listitem = Element('listitem')
149                 listitem.appendChild(paraElement('None'))
150                 params.appendChild(listitem)
151             section.appendChild(params)
152
153             section.appendChild(paraElement('Returns:'))
154             returns = dom.createElement('itemizedlist')
155             returns.appendChild(paramElement(None, func.returns))
156             section.appendChild(returns)
157
158             print(section.toxml())