File: test_docstrings.py

package info (click to toggle)
python-reportlab 3.3.0-2%2Bdeb9u1
  • links: PTS
  • area: main
  • in suites: stretch
  • size: 7,172 kB
  • sloc: python: 71,880; ansic: 19,093; xml: 1,494; makefile: 416; java: 193; sh: 100
file content (198 lines) | stat: -rw-r--r-- 6,428 bytes parent folder | download
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#!/usr/bin/env python
#Copyright ReportLab Europe Ltd. 2000-2016
#see license.txt for license details

"""This is a test on a package level that find all modules,
classes, methods and functions that do not have a doc string
and lists them in individual log files.

Currently, methods with leading and trailing double underscores
are skipped.
"""
from reportlab.lib.testutils import setOutDir,SecureTestCase, GlobDirectoryWalker, outputfile, printLocation
setOutDir(__name__)
import os, sys, glob, re, unittest, inspect
import reportlab
from reportlab.lib.utils import rl_exec, isPy3, isPyPy

def typ2is(typ):
    return getattr(inspect,'is'+typ)

_typ2key={
        'module':lambda x: (x[0],getattr(x[1],'__name__',''),getattr(x[1],'__path__',getattr(x,'__file__',''))),
        'class':lambda x: (x[0],getattr(x[1],'__name__',''),getattr(x[1],'__module__','')),
        'method':lambda x: (x[0],getattr(x[1],'__name__',''),getattr(x[1],'__module__','')),
        'function':lambda x: (x[0],getattr(x[1],'__name__',''),'???' if isPyPy else x[1].__code__.co_filename),
        }
def typ2key(typ):
    return _typ2key[typ]

def obj2typ(obj):
    for typ in ('function','module','class','method'):
        if typ2is(typ)(obj): return typ
    return None


def getClass(obj):
    try:
        return obj.__self__.__class__
    except:
        try:
            return obj.im_class
        except:
            return None

from pkgutil import iter_modules
def walk_packages_ex(path=None, prefix='', onerror=None, cond=None):
    def seen(p, m={}):
        if p in m:
            return True
        m[p] = True

    for importer, name, ispkg in iter_modules(path, prefix):
        if cond and not cond(importer,name,ispkg): continue
        yield importer, name, ispkg

        if ispkg:
            try:
                __import__(name)
            except ImportError:
                if onerror is not None:
                    onerror(name)
            except Exception:
                if onerror is not None:
                    onerror(name)
                else:
                    raise
            else:
                path = getattr(sys.modules[name], '__path__', None) or []

                # don't traverse path items we've seen before
                path = [p for p in path if not seen(p)]

                for item in walk_packages_ex(path, name+'.', onerror, cond):
                    yield item

def rl_module(i,name,pkg):
    return name=='reportlab' or name.startswith('reportlab.')

rl_modules = None
def getRLModules():
    "Get a list of all objects defined *somewhere* in a package."
    global rl_modules
    if rl_modules is None:
        rl_modules = []
        for _,name,_ in walk_packages_ex(cond=rl_module):
            rl_modules.append(name)
    return rl_modules

def getObjects(objects,lookup,mName,modBn,tobj):
    ttyp = obj2typ(tobj)
    for n in dir(tobj):
        obj = getattr(tobj,n,None)
        try:
            if obj in lookup: continue
        except:
            continue
        typ = obj2typ(obj)
        if typ in ('function','method'):
            if not isPyPy and os.path.splitext(obj.__code__.co_filename)[0]==modBn:
                lookup[obj] = 1
                objects.setdefault(typ if typ=='function' and ttyp=='module' else 'method',[]).append((mName,obj))
        elif typ=='class':
            if obj.__module__==mName:
                lookup[obj] = 1
                objects.setdefault(typ,[]).append((mName,obj))
                getObjects(objects,lookup,mName,modBn,obj)

def getModuleObjects(modules):
    objects = {}
    lookup = {}
    for mName in modules:
        try:
            NS = {}
            rl_exec("import %s as module" % mName,NS)
        except ImportError:
            continue
        else:
            module = NS['module']
        if module in lookup: continue

        lookup[module] = 1
        objects.setdefault('module',[]).append((mName, module))
        modBn = os.path.splitext(module.__file__)[0]
        getObjects(objects,lookup,mName,modBn,module)
    return objects

class DocstringTestCase(SecureTestCase):
    "Testing if objects in the ReportLab package have docstrings."

    def setUp(self):
        SecureTestCase.setUp(self)
        self.modules = getRLModules()
        self.objects = getModuleObjects(self.modules)

    def _writeLogFile(self, typ):
        "Write log file for different kind of documentable objects."

        objects = self.objects.get(typ,[])
        objects.sort(key=typ2key(typ))

        expl = {'function':'functions',
                'class':'classes',
                'method':'methods',
                'module':'modules'}[typ]

        path = outputfile("test_docstrings-%s.log" % expl)
        file = open(path, 'w')
        file.write('No doc strings found for the following %s below.\n\n' % expl)
        p = re.compile('__.+__')

        lines = []
        for name, obj in objects:
            if typ == 'method':
                n = obj.__name__
                # Skip names with leading and trailing double underscores.
                if p.match(n):
                    continue

            if not obj.__doc__ or len(obj.__doc__) == 0:
                if typ == 'function':
                    lines.append("%s.%s\n" % (name, obj.__name__))
                elif typ == 'class':
                    lines.append("%s.%s\n" % (obj.__module__, getattr(obj,'__qualname__',getattr(obj,'__name__','[unknown __name__]'))))
                else:
                    lines.append("%s\n" % (getattr(obj,'__qualname__',getattr(obj,'__name__','[unknown __name__]'))))

        lines.sort()
        for line in lines:
            file.write(line)

        file.close()

    def test0(self):
        "Test if functions have a doc string."
        self._writeLogFile('function')

    def test1(self):
        "Test if classes have a doc string."
        self._writeLogFile('class')

    def test2(self):
        "Test if methods have a doc string."
        self._writeLogFile('method')

    def test3(self):
        "Test if modules have a doc string."
        self._writeLogFile('module')

def makeSuite():
    suite = unittest.TestSuite()
    loader = unittest.TestLoader()
    if sys.platform[:4] != 'java': suite.addTest(loader.loadTestsFromTestCase(DocstringTestCase))
    return suite

#noruntests
if __name__ == "__main__":
    unittest.TextTestRunner().run(makeSuite())
    printLocation()