ActiveState Code

Recipe 355731: Docstring coverage.


Tool to examine lack of docstrings in a module.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import compiler

usage = '''python coverage.py <pythonsourcefile>

Prints a rundown of the classes, functions, and methods in the given module 
that have not been given a docstring.
'''

class DocStringCoverageVisitor(compiler.visitor.ASTVisitor):
    
    def __init__(self, filename):
        self.currentnode = []
        self.symbolcount = 0
        ast = compiler.parseFile(filename)
        compiler.walk(ast, self)
    
    def visitModule(self, module):
        self.symbolcount += 1
        node = (module.doc is not None and module.doc.strip() != '', [])
        self.currentnode.append(node)
        compiler.walk(module.node, self)
        self.result = self.currentnode.pop()
    
    def visitClass(self, clazz):
        self.symbolcount += 1
        isDoc = clazz.doc is not None and clazz.doc.strip() != ''
        node = (clazz.name, isDoc, [])
        self.currentnode[-1][-1].append(node)
        self.currentnode.append(node)
        compiler.walk(clazz.code, self)
        self.currentnode.pop()
    
    def visitFunction(self, func):
        self.symbolcount += 1
        isDoc = func.doc is not None and func.doc.strip() != ''
        node = (func.name, isDoc, [])
        self.currentnode[-1][-1].append(node)
        self.currentnode.append(node)
        compiler.walk(func.code, self)
        self.currentnode.pop()
    
    def getResult(self):
        return self.result

def main():
    import sys, os

    def printDocstring(base, node):
        name, isDoc, childNodes = node
        if isDoc == False:
            print 'No docstring for %s%s!' % (base, name)
        for symbol in childNodes:
            printDocstring('%s.' % name, symbol)
    
    if len(sys.argv) != 2:
        print usage
        raise SystemExit
    module = DocStringCoverageVisitor(sys.argv[1]).getResult()
    if not module[0]:
        print "No module dostring!"
    for symbol in module[1]:
        printDocstring('', symbol)
        

if __name__ == '__main__':
    main()

Discussion

I should point out that the code lacks docstrings so it can be tested on itself. The code doesn't work on classes or functions that are eval'd into existence.

Comments

  1. 1. At 1:52 p.m. on 3 jan 2005, Jean Brouwers said:

    There are at least two errors in this recipe.

    class DocStringCoverageVisitor(compiler.visitor.ASTVisitor):
        symbolcount = 0  # add this line
        ...
    
        def visitClass(self, clazz):
            ...
            isDoc = clazz.doc is not None and clazz.doc.strip() != ''  # was func.clazz.strip()
            ...
    

    The second change may not be correct. There may be other issues.

  2. 2. At 9:59 a.m. on 6 apr 2005, James Harlow (the author) said:

    Thanks! thanks very much for spotting these.

Sign in to comment