Generating PythonDoc Pages for Virtual Modules

November 2003 | Fredrik Lundh

PythonDoc 2 can be used both as a command-line utility, and as a Python module. The latter can come in handy in situations where there’s not a direct match between the Python source files, and the programming interface exposed to the user. In such cases, you can use PythonDoc’s parse function to read in the documentation for the actual source files, and manipulate the resulting module descriptions in Python before generating the output files.

For example, the WCK library consists of a number of implementation modules, and a package __init__.py that pulls everything together. In the Tkinter implementation, that __init__.py file looks something like this:

# WCK/__init__.py

from wckTkinter import *
from Utils import *

In other words, the user gets access to all functions and classes in both the wckTkinter module and the Utils module simply by importing the WCK package itself. Which is exactly what the user is supposed to do, of course. The other modules are just implementation details.

Here’s a small script that parses both modules, and merges the result into a single WCK module description:

from pythondoc import parse, CompactHTML
from elementtree.ElementTree import Element

module = Element("module", name="WCK")

for file in ["WCK/wckTkinter.py", "WCK/Utils.py"]:
    elem = parse(file)
    for elem in elem:
        if module and elem.tag == "info":
            # skip all module info sections except the first
            continue
        module.append(elem)

formatter = CompactHTML()
print formatter.save(module, "WCK"), "ok"

The output from this script will look something like this: The WCK Module.

 

Comment:

John Machin pointed out that this doesn't sort the items in the right order; the CompactHTML renderer sorts on (subcomponent, name) instead of (module, name). Here's a work around (insert after the module append loop):

# move all objects to the "virtual" namespace
for elem in module.getiterator():
    if elem.tag in ("param", "keyparam", "exception"):
        continue # don't sort params
    name = elem.get("name")
    if name:
        # change *.foo.bar to WCK.foo.bar
        # print elem.tag, elem.get("name"), "->",
        elem.set("name", ".".join(["WCK"] + name.split(".")[1:]))
        # print elem.get("name")

Posted by Fredrik (2006-11-18)

A Django site. rendered by a django application. hosted by webfaction.