Package epydoc :: Module checker
[hide private]
[frames] | no frames]

Source Code for Module epydoc.checker

  1  # 
  2  # objdoc: epydoc documentation completeness checker 
  3  # Edward Loper 
  4  # 
  5  # Created [01/30/01 05:18 PM] 
  6  # $Id: checker.py 1366 2006-09-07 15:54:59Z edloper $ 
  7  # 
  8   
  9  """ 
 10  Documentation completeness checker.  This module defines a single 
 11  class, C{DocChecker}, which can be used to check the that specified 
 12  classes of objects are documented. 
 13  """ 
 14  __docformat__ = 'epytext en' 
 15   
 16  ################################################## 
 17  ## Imports 
 18  ################################################## 
 19   
 20  import re, sys, os.path, string 
 21  from xml.dom.minidom import Text as _Text 
 22  from epydoc.apidoc import * 
 23   
 24  # The following methods may be undocumented: 
 25  _NO_DOCS = ['__hash__', '__repr__', '__str__', '__cmp__'] 
 26   
 27  # The following methods never need descriptions, authors, or 
 28  # versions: 
 29  _NO_BASIC = ['__hash__', '__repr__', '__str__', '__cmp__'] 
 30   
 31  # The following methods never need return value descriptions. 
 32  _NO_RETURN = ['__init__', '__hash__', '__repr__', '__str__', '__cmp__'] 
 33   
 34  # The following methods don't need parameters documented: 
 35  _NO_PARAM = ['__cmp__'] 
 36   
37 -class DocChecker:
38 """ 39 Documentation completeness checker. C{DocChecker} can be used to 40 check that specified classes of objects are documented. To check 41 the documentation for a group of objects, you should create a 42 C{DocChecker} from a L{DocIndex<apidoc.DocIndex>} that documents 43 those objects; and then use the L{check} method to run specified 44 checks on the objects' documentation. 45 46 What checks are run, and what objects they are run on, are 47 specified by the constants defined by C{DocChecker}. These 48 constants are divided into three groups. 49 50 - Type specifiers indicate what type of objects should be 51 checked: L{MODULE}; L{CLASS}; L{FUNC}; L{VAR}; L{IVAR}; 52 L{CVAR}; L{PARAM}; and L{RETURN}. 53 - Public/private specifiers indicate whether public or private 54 objects should be checked: L{PRIVATE}. 55 - Check specifiers indicate what checks should be run on the 56 objects: L{TYPE}; L{DESCR}; L{AUTHOR}; 57 and L{VERSION}. 58 59 The L{check} method is used to perform a check on the 60 documentation. Its parameter is formed by or-ing together at 61 least one value from each specifier group: 62 63 >>> checker.check(DocChecker.MODULE | DocChecker.DESCR) 64 65 To specify multiple values from a single group, simply or their 66 values together: 67 68 >>> checker.check(DocChecker.MODULE | DocChecker.CLASS | 69 ... DocChecker.FUNC ) 70 71 @group Types: MODULE, CLASS, FUNC, VAR, IVAR, CVAR, PARAM, 72 RETURN, ALL_T 73 @type MODULE: C{int} 74 @cvar MODULE: Type specifier that indicates that the documentation 75 of modules should be checked. 76 @type CLASS: C{int} 77 @cvar CLASS: Type specifier that indicates that the documentation 78 of classes should be checked. 79 @type FUNC: C{int} 80 @cvar FUNC: Type specifier that indicates that the documentation 81 of functions should be checked. 82 @type VAR: C{int} 83 @cvar VAR: Type specifier that indicates that the documentation 84 of module variables should be checked. 85 @type IVAR: C{int} 86 @cvar IVAR: Type specifier that indicates that the documentation 87 of instance variables should be checked. 88 @type CVAR: C{int} 89 @cvar CVAR: Type specifier that indicates that the documentation 90 of class variables should be checked. 91 @type PARAM: C{int} 92 @cvar PARAM: Type specifier that indicates that the documentation 93 of function and method parameters should be checked. 94 @type RETURN: C{int} 95 @cvar RETURN: Type specifier that indicates that the documentation 96 of return values should be checked. 97 @type ALL_T: C{int} 98 @cvar ALL_T: Type specifier that indicates that the documentation 99 of all objects should be checked. 100 101 @group Checks: TYPE, AUTHOR, VERSION, DESCR, ALL_C 102 @type TYPE: C{int} 103 @cvar TYPE: Check specifier that indicates that every variable and 104 parameter should have a C{@type} field. 105 @type AUTHOR: C{int} 106 @cvar AUTHOR: Check specifier that indicates that every object 107 should have an C{author} field. 108 @type VERSION: C{int} 109 @cvar VERSION: Check specifier that indicates that every object 110 should have a C{version} field. 111 @type DESCR: C{int} 112 @cvar DESCR: Check specifier that indicates that every object 113 should have a description. 114 @type ALL_C: C{int} 115 @cvar ALL_C: Check specifier that indicates that all checks 116 should be run. 117 118 @group Publicity: PRIVATE 119 @type PRIVATE: C{int} 120 @cvar PRIVATE: Specifier that indicates that private objects should 121 be checked. 122 """ 123 # Types 124 MODULE = 1 125 CLASS = 2 126 FUNC = 4 127 VAR = 8 128 #IVAR = 16 129 #CVAR = 32 130 PARAM = 64 131 RETURN = 128 132 PROPERTY = 256 133 ALL_T = 1+2+4+8+16+32+64+128+256 134 135 # Checks 136 TYPE = 256 137 AUTHOR = 1024 138 VERSION = 2048 139 DESCR = 4096 140 ALL_C = 256+512+1024+2048+4096 141 142 # Private/public 143 PRIVATE = 16384 144 145 ALL = ALL_T + ALL_C + PRIVATE 146
147 - def __init__(self, docindex):
148 """ 149 Create a new C{DocChecker} that can be used to run checks on 150 the documentation of the objects documented by C{docindex} 151 152 @param docindex: A documentation map containing the 153 documentation for the objects to be checked. 154 @type docindex: L{Docindex<apidoc.DocIndex>} 155 """ 156 self._docindex = docindex 157 158 # Initialize instance variables 159 self._checks = 0 160 self._last_warn = None 161 self._out = sys.stdout 162 self._num_warnings = 0
163
164 - def check(self, *check_sets):
165 """ 166 Run the specified checks on the documentation of the objects 167 contained by this C{DocChecker}'s C{DocIndex}. Any errors found 168 are printed to standard out. 169 170 @param check_sets: The checks that should be run on the 171 documentation. This value is constructed by or-ing 172 together the specifiers that indicate which objects should 173 be checked, and which checks should be run. See the 174 L{module description<checker>} for more information. 175 If no checks are specified, then a default set of checks 176 will be run. 177 @type check_sets: C{int} 178 @return: True if no problems were found. 179 @rtype: C{boolean} 180 """ 181 if not check_sets: 182 check_sets = (DocChecker.MODULE | DocChecker.CLASS | 183 DocChecker.FUNC | DocChecker.VAR | 184 DocChecker.DESCR,) 185 186 self._warnings = {} 187 log.start_progress('Checking docs') 188 for j, checks in enumerate(check_sets): 189 self._check(checks) 190 log.end_progress() 191 192 for (warning, docs) in self._warnings.items(): 193 docs = sorted(docs) 194 docnames = '\n'.join([' - %s' % self._name(d) for d in docs]) 195 log.warning('%s:\n%s' % (warning, docnames))
196
197 - def _check(self, checks):
198 self._checks = checks 199 200 # Get the list of objects to check. 201 valdocs = sorted(self._docindex.reachable_valdocs( 202 imports=False, packages=False, bases=False, submodules=False, 203 subclasses=False, private = (checks & DocChecker.PRIVATE))) 204 docs = set() 205 for d in valdocs: 206 if not isinstance(d, GenericValueDoc): docs.add(d) 207 for doc in valdocs: 208 if isinstance(doc, NamespaceDoc): 209 for d in doc.variables.values(): 210 if isinstance(d.value, GenericValueDoc): docs.add(d) 211 212 for i, doc in enumerate(sorted(docs)): 213 if isinstance(doc, ModuleDoc): 214 self._check_module(doc) 215 elif isinstance(doc, ClassDoc): 216 self._check_class(doc) 217 elif isinstance(doc, RoutineDoc): 218 self._check_func(doc) 219 elif isinstance(doc, PropertyDoc): 220 self._check_property(doc) 221 elif isinstance(doc, VariableDoc): 222 self._check_var(doc) 223 else: 224 log.error("Don't know how to check %r" % doc)
225
226 - def _name(self, doc):
227 name = str(doc.canonical_name) 228 if isinstance(doc, RoutineDoc): name += '()' 229 return name
230
231 - def _check_basic(self, doc):
232 """ 233 Check the description, author, version, and see-also fields of 234 C{doc}. This is used as a helper function by L{_check_module}, 235 L{_check_class}, and L{_check_func}. 236 237 @param doc: The documentation that should be checked. 238 @type doc: L{APIDoc} 239 @rtype: C{None} 240 """ 241 if ((self._checks & DocChecker.DESCR) and 242 (doc.descr in (None, UNKNOWN))): 243 if doc.docstring in (None, UNKNOWN): 244 self.warning('Undocumented', doc) 245 else: 246 self.warning('No description', doc) 247 if self._checks & DocChecker.AUTHOR: 248 for tag, arg, descr in doc.metadata: 249 if 'author' == tag: break 250 else: 251 self.warning('No authors', doc) 252 if self._checks & DocChecker.VERSION: 253 for tag, arg, descr in doc.metadata: 254 if 'version' == tag: break 255 else: 256 self.warning('No version', doc)
257
258 - def _check_module(self, doc):
259 """ 260 Run checks on the module whose APIDoc is C{doc}. 261 262 @param doc: The APIDoc of the module to check. 263 @type doc: L{APIDoc} 264 @rtype: C{None} 265 """ 266 if self._checks & DocChecker.MODULE: 267 self._check_basic(doc)
268
269 - def _check_class(self, doc):
270 """ 271 Run checks on the class whose APIDoc is C{doc}. 272 273 @param doc: The APIDoc of the class to check. 274 @type doc: L{APIDoc} 275 @rtype: C{None} 276 """ 277 if self._checks & DocChecker.CLASS: 278 self._check_basic(doc)
279
280 - def _check_property(self, doc):
281 if self._checks & DocChecker.PROPERTY: 282 self._check_basic(doc)
283
284 - def _check_var(self, doc):
285 """ 286 Run checks on the variable whose documentation is C{var} and 287 whose name is C{name}. 288 289 @param doc: The documentation for the variable to check. 290 @type doc: L{APIDoc} 291 @rtype: C{None} 292 """ 293 if self._checks & DocChecker.VAR: 294 if (self._checks & (DocChecker.DESCR|DocChecker.TYPE) and 295 doc.descr in (None, UNKNOWN) and 296 doc.type_descr in (None, UNKNOWN) and 297 doc.docstring in (None, UNKNOWN)): 298 self.warning('Undocumented', doc) 299 else: 300 if (self._checks & DocChecker.DESCR and 301 doc.descr in (None, UNKNOWN)): 302 self.warning('No description', doc) 303 if (self._checks & DocChecker.TYPE and 304 doc.type_descr in (None, UNKNOWN)): 305 self.warning('No type information', doc)
306
307 - def _check_func(self, doc):
308 """ 309 Run checks on the function whose APIDoc is C{doc}. 310 311 @param doc: The APIDoc of the function to check. 312 @type doc: L{APIDoc} 313 @rtype: C{None} 314 """ 315 name = doc.canonical_name 316 if (self._checks & DocChecker.FUNC and 317 doc.docstring in (None, UNKNOWN) and 318 doc.canonical_name[-1] not in _NO_DOCS): 319 self.warning('Undocumented', doc) 320 return 321 if (self._checks & DocChecker.FUNC and 322 doc.canonical_name[-1] not in _NO_BASIC): 323 self._check_basic(doc) 324 if (self._checks & DocChecker.RETURN and 325 doc.canonical_name[-1] not in _NO_RETURN): 326 if (doc.return_type in (None, UNKNOWN) and 327 doc.return_descr in (None, UNKNOWN)): 328 self.warning('No return descr', doc) 329 if (self._checks & DocChecker.PARAM and 330 doc.canonical_name[-1] not in _NO_PARAM): 331 if doc.arg_descrs in (None, UNKNOWN): 332 self.warning('No argument info', doc) 333 else: 334 args_with_descr = [] 335 for arg, descr in doc.arg_descrs: 336 if isinstance(arg, basestring): 337 args_with_descr.append(arg) 338 else: 339 args_with_descr += arg 340 for posarg in doc.posargs: 341 if (self._checks & DocChecker.DESCR and 342 posarg not in args_with_descr): 343 self.warning('Argument(s) not described', doc) 344 if (self._checks & DocChecker.TYPE and 345 posarg not in doc.arg_types): 346 self.warning('Argument type(s) not described', doc)
347
348 - def warning(self, msg, doc):
349 self._warnings.setdefault(msg,set()).add(doc)
350