Documenting algorithms in Python (using pydoc)

By clackwell

Python’s pydoc allows to include documentation for a method in the source code, in the first lines of a method’s body for example:

def test():
    """Documentation for method test."""

    # If file exists:
    ...
        # Delete file
        ...
    # Do this
    ...
    # Do that
    ...

But what if you want to document the algorithm used in the body of that method so that it shows up in the pydoc output as well? You could just add it to the pydoc comment explicitly:

def test():
    """Documentation for method test.

    It uses the following steps:
        If file exists
            Delete file
        Do this
        Do that"""

    # If file exists:
    ...
        # Delete file
        ...
    # Do this
    ...
    # Do that
    ...

Because the code already contains the documentation of each step adding each to the pydoc comment is uncomfortable, a duplication of effort.

By “extending” pydoc the duplication effort can be removed, so that documenting the algorithm could look like this:

def test():
    """Documentation for method test."""

    #ALGO: If file exists:
    ...
        #ALGO: Delete file
        ...
    #ALGO: Do this
    ...
    #ALGO: Do that
    ...

Note how the prefix “ALGO” in the comments is used to mark a comment as a comment for the algorithm.

Here is how to “extend” pydoc to support this functionality (contents of a file “pydoc_algo.py” created by you):

import pydoc
import inspect

def test():
    """This is an example of algorithm documentation entries.

    Note using capitalized keyword "ALGO" to see
    algorithm pydoc entries more quickly in the
    code.

    Also note the use of "pass" in the example: If
    a comment is not followed by at least one line
    of actual code it does not end up in
    inspect.getsource() and inspect.getsourcelines."""

    #ALGO: If file exists:
    if True:
        #ALGO: Delete file
        pass

    #ALGO: Create the file
    pass

    #ALGO: Open file
    pass

    #ALGO: Write data to file
    pass

    #ALGO: Close file
    pass

def getdoc(object):
    algoComments = []
    sourceLines = inspect.getsourcelines(object)[0]
    for line in sourceLines:
        lineLower = line.lower()

        while True:
            s = "# algo "
            if lineLower.find(s) != -1:
                break
            s = "# algo: "
            if lineLower.find(s) != -1:
                break
            s = "#algo "
            if lineLower.find(s) != -1:
                break
            s = "#algo: "
            if lineLower.find(s) != -1:
                break

            s = None
            break

        if s is not None:
            start       = lineLower.find(s)
            end         = start + len(s)
            indent      = line[:start - 1]
            algoComment = line[end:]
            algoComments.append(indent + algoComment)

    s = inspect_getdoc(object)

    if len(algoComments) > 0:
        s += "\n\nAlgorithm:\n"
        for c in algoComments:
            s += c

    return s

# "Install" the extension by replacing inspect.getdoc().
# Keep the reference to the previous inspect.getdoc()
# to call it ourselves.
inspect_getdoc = inspect.getdoc
inspect.getdoc = getdoc

if __name__ == "__main__":
    pydoc.help(test)

Here is an example call:

>>> import pydoc
>>> pydoc.help(pydoc_algo.test)
Help on function test in module pydoc_algo:

test()
    This is an example of algo documentation entries.

    Note using capitalized keyword "ALGO" to see
    algorithm pydoc entries more quickly in the
    code.

    Also note the use of "pass" in the example: If
    a comment is not followed by at least one line
    of actual code it does not end up in
    inspect.getsource() and inspect.getsourcelines.

    Algorithm:
       If file exists:
           Delete file
       Create the file
       Open file
       Write data to file
       Close file

>>>

This approach could be useful for “To do” entries too (“#ToDo: Do this and that here in the code!”).

Leave a Reply