Welcome, guest | Sign In | My Account | Store | Cart

Tool to examine lack of docstrings in a module.

Python, 66 lines
 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()

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.

2 comments

Jean Brouwers 16 years, 11 months ago  # | flag

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.

James Harlow (author) 16 years, 8 months ago  # | flag

Thanks! thanks very much for spotting these.