-#!/usr/bin/python
+#!/usr/bin/env python3
#
# Generates a DocBook section documenting all PLCAPI methods on
# stdout.
# Mark Huang <mlhuang@cs.princeton.edu>
# Copyright (C) 2006 The Trustees of Princeton University
#
-# $Id$
-#
+
+# dec 2018
+# going for python3; xml.dom.minidom has changed a lot
+# working around the changes in a rather quick & dirty way
import xml.dom.minidom
-from xml.dom.minidom import Element, Text
-import codecs
+from xml.dom.minidom import Element, parseString
-from PLC.API import PLCAPI
-from PLC.Method import *
+from PLC.Parameter import Parameter, Mixed, xmlrpc_type, python_type
-api = PLCAPI(None)
+# can no longer create elements out of a document
+dom = parseString('<dummydoc/>')
-# xml.dom.minidom.Text.writexml adds surrounding whitespace to textual
-# data when pretty-printing. Override this behavior.
-class TrimText(Text):
- def writexml(self, writer, indent="", addindent="", newl=""):
- Text.writexml(self, writer, "", "", "")
+def text_node(text):
+ global dom
+ return dom.createTextNode(text)
+
+class TextElement(Element):
+ """<tagName>text</tagName>"""
+ def __init__(self, tagName, text = None):
+ Element.__init__(self, tagName)
+ if text is not None:
+ self.appendChild(text_node(text))
-class TrimTextElement(Element):
def writexml(self, writer, indent="", addindent="", newl=""):
writer.write(indent)
Element.writexml(self, writer, "", "", "")
writer.write(newl)
-class simpleElement(TrimTextElement):
- """<tagName>text</tagName>"""
- def __init__(self, tagName, text = None):
- TrimTextElement.__init__(self, tagName)
- if text is not None:
- t = TrimText()
- t.data = unicode(text)
- self.appendChild(t)
+class simpleElement(TextElement):
+ def __init__(self, *args, **kwds):
+ super().__init__(*args, **kwds)
class paraElement(simpleElement):
"""<para>text</para>"""
for paragraph in paragraphs:
self.appendChild(paraElement(paragraph))
-class entryElement(simpleElement):
- """<entry>text</entry>"""
- def __init__(self, text = None):
- simpleElement.__init__(self, 'entry', text)
-
-class rowElement(Element):
- """
- <row>
- <entry>entries[0]</entry>
- <entry>entries[1]</entry>
- ...
- </row>
- """
-
- def __init__(self, entries = None):
- Element.__init__(self, 'row')
- if entries:
- for entry in entries:
- if isinstance(entry, entryElement):
- self.appendChild(entry)
- else:
- self.appendChild(entryElement(entry))
-
-class informaltableElement(Element):
- """
- <informaltable>
- <tgroup>
- <thead>
- <row>
- <entry>label1</entry>
- <entry>label2</entry>
- ...
- </row>
- </thead>
- <tbody>
- <row>
- <entry>row1value1</entry>
- <entry>row1value2</entry>
- ...
- </row>
- ...
- </tbody>
- </tgroup>
- </informaltable>
- """
-
- def __init__(self, head = None, rows = None):
- Element.__init__(self, 'informaltable')
- tgroup = Element('tgroup')
- self.appendChild(tgroup)
- if head:
- thead = Element('thead')
- tgroup.appendChild(thead)
- if isinstance(head, rowElement):
- thead.appendChild(head)
- else:
- thead.appendChild(rowElement(head))
- if rows:
- tbody = Element('tbody')
- tgroup.appendChild(tbody)
- for row in rows:
- if isinstance(row, rowElement):
- tbody.appendChild(row)
- else:
- tobdy.appendChild(rowElement(row))
- cols = len(thead.childNodes[0].childNodes)
- tgroup.setAttribute('cols', str(cols))
-
-def parameters(param, name, optional, default, doc, indent, step):
- """Format a parameter into parameter row(s)."""
-
- rows = []
-
- row = rowElement()
- rows.append(row)
-
- # Parameter name
- entry = entryElement()
- entry.appendChild(simpleElement('literallayout', indent + name))
- row.appendChild(entry)
-
- # Parameter type
- param_type = python_type(param)
- row.appendChild(entryElement(xmlrpc_type(param_type)))
-
- # Whether parameter is optional
- row.appendChild(entryElement(str(bool(optional))))
-
- # Parameter default
- if optional and default is not None:
- row.appendChild(entryElement(unicode(default)))
+def param_type(param):
+ """Return the XML-RPC type of a parameter."""
+ if isinstance(param, Mixed) and len(param):
+ subtypes = [param_type(subparam) for subparam in param]
+ return " or ".join(subtypes)
+ elif isinstance(param, (list, tuple, set)) and len(param):
+ return "array of " + " or ".join([param_type(subparam) for subparam in param])
else:
- row.appendChild(entryElement())
-
- # Parameter documentation
- row.appendChild(entryElement(doc))
-
- # Indent the name of each sub-parameter
- subparams = []
- if isinstance(param, dict):
- subparams = param.iteritems()
- elif isinstance(param, Mixed):
- subparams = [(name, subparam) for subparam in param]
- elif isinstance(param, (list, tuple)):
- subparams = [("", subparam) for subparam in param]
-
- for name, subparam in subparams:
- if isinstance(subparam, Parameter):
- (optional, default, doc) = (subparam.optional, subparam.default, subparam.doc)
- else:
- # All named sub-parameters are optional if not otherwise specified
- (optional, default, doc) = (True, None, "")
- rows += parameters(subparam, name, optional, default, doc, indent + step, step)
-
- return rows
-
-for method in api.methods:
- func = api.callable(method)
- (min_args, max_args, defaults) = func.args()
-
- section = Element('section')
- section.setAttribute('id', func.name)
- section.appendChild(simpleElement('title', func.name))
-
- para = paraElement('Status:')
- para.appendChild(blockquoteElement(func.status))
- section.appendChild(para)
-
- prototype = "%s (%s)" % (method, ", ".join(max_args))
- para = paraElement('Prototype:')
- para.appendChild(blockquoteElement(prototype))
- section.appendChild(para)
-
- para = paraElement('Description:')
- para.appendChild(blockquoteElement(func.__doc__))
- section.appendChild(para)
-
- para = paraElement('Parameters:')
- blockquote = blockquoteElement()
- para.appendChild(blockquote)
- section.appendChild(para)
-
- head = rowElement(['Name', 'Type', 'Optional', 'Default', 'Description'])
- rows = []
-
- indent = " "
- for name, param, default in zip(max_args, func.accepts, defaults):
- optional = name not in min_args
+ return xmlrpc_type(python_type(param))
+
+class paramElement(Element):
+ """An optionally named parameter."""
+ def __init__(self, name, param):
+ # <listitem>
+ Element.__init__(self, 'listitem')
+
+ global dom
+ description = dom.createElement('para')
+
+ if name:
+ description.appendChild(simpleElement('parameter', name))
+ description.appendChild(text_node(": "))
+
+ description.appendChild(text_node(param_type(param)))
+
+ if isinstance(param, (list, tuple, set)) and len(param) == 1:
+ param = param[0]
+
if isinstance(param, Parameter):
- doc = param.doc
- else:
- doc = ""
- rows += parameters(param, name, optional, default, doc, "", indent)
-
- if rows:
- informaltable = informaltableElement(head, rows)
- informaltable.setAttribute('frame', "none")
- informaltable.setAttribute('rules', "rows")
- blockquote.appendChild(informaltable)
- else:
- blockquote.appendChild(paraElement("None"))
+ description.appendChild(text_node(", " + param.doc))
+ param = param.type
+
+ self.appendChild(description)
+
+ if isinstance(param, dict):
+ itemizedlist = dom.createElement('itemizedlist')
+ self.appendChild(itemizedlist)
+ for name, subparam in param.items():
+ itemizedlist.appendChild(paramElement(name, subparam))
+
+ elif isinstance(param, (list, tuple, set)) and len(param):
+ itemizedlist = dom.createElement('itemizedlist')
+ self.appendChild(itemizedlist)
+ for subparam in param:
+ itemizedlist.appendChild(paramElement(None, subparam))
+
+class DocBook:
+
+ def __init__ (self, functions_list):
+ self.functions_list = functions_list
+
+ def Process (self):
+
+ global dom
+
+ for func in self.functions_list:
+ method = func.name
+
+ if func.status == "deprecated":
+ continue
+
+ (min_args, max_args, defaults) = func.args()
+
+ # with python3 it looks like an element can't be sfa_created
+ # outside of a document
+ section = dom.createElement('section')
+ section.setAttribute('id', func.name)
+ section.appendChild(simpleElement('title', func.name))
+
+ prototype = "%s (%s)" % (method, ", ".join(max_args))
+ para = paraElement('Prototype:')
+ para.appendChild(blockquoteElement(prototype))
+ section.appendChild(para)
+
+ para = paraElement('Description:')
+ para.appendChild(blockquoteElement(func.__doc__))
+ section.appendChild(para)
+
+ para = paraElement('Allowed Roles:')
+ para.appendChild(blockquoteElement(", ".join(func.roles)))
+ section.appendChild(para)
+
+ section.appendChild(paraElement('Parameters:'))
+ params = Element('itemizedlist')
+ if func.accepts:
+ for name, param, default in zip(max_args, func.accepts, defaults):
+ params.appendChild(paramElement(name, param))
+ else:
+ listitem = Element('listitem')
+ listitem.appendChild(paraElement('None'))
+ params.appendChild(listitem)
+ section.appendChild(params)
+
+ section.appendChild(paraElement('Returns:'))
+ returns = dom.createElement('itemizedlist')
+ returns.appendChild(paramElement(None, func.returns))
+ section.appendChild(returns)
- print section.toprettyxml(encoding = "UTF-8")
+ print(section.toxml())