We're back after a server migration that caused effbot.org to fall over a bit harder than expected. Expect some glitches.

Writing PythonDoc Plugins

October 26, 2003 | Fredrik Lundh

PythonDoc 2.0 supports pluggable output generators. You can use custom plugins to generate HTML that matches your corporate documentation standard, to generate PDF versions of the documentation (using ReportLab), to check that all methods and classes are properly documented, etc.

Writing Generator Plugins

An output generator is a Python module that’s imported by the PythonDoc tool when it starts. For each source file that contains PythonDoc markup, the tool builds an XML structure and passes it to the generator.

Here’s how it works:

  1. If the -O option is used, PythonDoc imports the specified module. For example, -Ooutput imports the output module. -Otools.myformatter imports the myformatter module from the tools package.

    import tools.myformatter as formatter
    
  2. Before PythonDoc starts parsing, it calls the PythonDocGenerator object in the imported module, with a dictionary containing any configuration options (as specified with the -D option; -Dkey sets dictionary member key to None; -Dkey=value sets dictionary member key to value). The return value from this call is used as the generator instance. The PythonDocGenerator object is usually a class, but can also be a factory function.

    generator = formatter.PythonDocGenerator(options)
    
  3. For each file, PythonDoc calls the save method on the generator instance, passing in an element structure and a filename prefix. The structure contains the infoset for this module. The prefix is usually pythondoc- followed by the full name of the module; you can usually just add a suitable extension. If the save method writes anything to disk, it should return a string (usually the complete filename). PythonDoc prints this string, followed by the string “ ok“.

    status = generator.save(module_element, prefix)
    if status:
        print status, "ok"
    
  4. When PythonDoc has finished parsing the source files, it calls the optional done method on the generator instance. If this method exists and returns a string, that string is printed, followed by the string “ ok“. You don’t have to provide this method; if looking up done results in an AttributeError, the PythonDoc tool proceeds without any complaints.

    try:
        done = generator.done
    except AttributeError:
        pass
    else:
        status = done()
        if status:
            print status, "ok"
    

Here’s an example:

# File: xml.py

import elementtree.ElementTree as ET

class PythonDocGenerator:

    def __init__(self, options):
        self.encoding = options.get("encoding")

    def save(self, module, file):
        file = file + ".xml"
        tree = ET.ElementTree(module)
        tree.write(file, self.encoding)
        return file

    def done(self):
        pass

This example works like the standard XML writer, except that you can use -Dencoding=charset to specify the encoding.

Note that the module argument is a plain Element instance; the example wraps it in an ElementTree wrapper to be able to write it out as XML.

Also note that if you use this generator with the -x option, the output from your generator will be overwritten by XML files produced by the standard XML writer; the custom generator is always called first.