1   
  2   
  3   
  4   
  5   
  6   
  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   
 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   
 25  _NO_DOCS = ['__hash__', '__repr__', '__str__', '__cmp__'] 
 26   
 27   
 28   
 29  _NO_BASIC = ['__hash__', '__repr__', '__str__', '__cmp__'] 
 30   
 31   
 32  _NO_RETURN = ['__init__', '__hash__', '__repr__', '__str__', '__cmp__'] 
 33   
 34   
 35  _NO_PARAM = ['__cmp__'] 
 36   
 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{DESCR_LAZY}; 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 | DocChecker.DESCR_LAZY) 
 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_LAZY, 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       
124      MODULE = 1 
125      CLASS  = 2 
126      FUNC   = 4 
127      VAR    = 8 
128       
129       
130      PARAM  = 64 
131      RETURN = 128 
132      PROPERTY = 256 
133      ALL_T  = 1+2+4+8+16+32+64+128+256 
134   
135       
136      TYPE = 256 
137      AUTHOR = 1024 
138      VERSION = 2048 
139      DESCR = 4096 
140      ALL_C = 256+512+1024+2048+4096 
141   
142       
143      PRIVATE = 16384 
144   
145      ALL = ALL_T + ALL_C + PRIVATE 
146   
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           
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 checks: 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 checks: 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   
198          self._checks = checks 
199           
200           
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   
230   
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{ObjDoc} 
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               
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           
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   
283   
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{Doc} 
291          @param check_type: Whether or not the variable's type should 
292              be checked.  This is used to allow varargs and keyword 
293              parameters to have no type specified. 
294          @rtype: C{None} 
295          """ 
296          if self._checks & DocChecker.VAR: 
297              if (self._checks & (DocChecker.DESCR|DocChecker.TYPE) and 
298                  doc.descr in (None, UNKNOWN) and 
299                  doc.type_descr in (None, UNKNOWN) and 
300                  doc.docstring in (None, UNKNOWN)): 
301                  self.warning('Undocumented', doc) 
302              else: 
303                  if (self._checks & DocChecker.DESCR and 
304                      doc.descr in (None, UNKNOWN)): 
305                      self.warning('No description', doc) 
306                  if (self._checks & DocChecker.TYPE and 
307                      doc.type_descr in (None, UNKNOWN)): 
308                      self.warning('No type information', doc) 
 309               
311          """ 
312          Run checks on the function whose APIDoc is C{doc}. 
313           
314          @param doc: The APIDoc of the function to check. 
315          @type doc: L{APIDoc} 
316          @rtype: C{None} 
317          """ 
318          name = doc.canonical_name 
319          if (self._checks & DocChecker.FUNC and 
320              doc.docstring in (None, UNKNOWN) and 
321              doc.canonical_name[-1] not in _NO_DOCS): 
322              self.warning('Undocumented', doc) 
323              return 
324          if (self._checks & DocChecker.FUNC and 
325              doc.canonical_name[-1] not in _NO_BASIC): 
326                  self._check_basic(doc) 
327          if (self._checks & DocChecker.RETURN and 
328              doc.canonical_name[-1] not in _NO_RETURN): 
329              if (doc.return_type in (None, UNKNOWN) and 
330                  doc.return_descr in (None, UNKNOWN)): 
331                  self.warning('No return descr', doc) 
332          if (self._checks & DocChecker.PARAM and 
333              doc.canonical_name[-1] not in _NO_PARAM): 
334              if doc.arg_descrs in (None, UNKNOWN): 
335                  self.warning('No argument info', doc) 
336              else: 
337                  args_with_descr = [] 
338                  for arg, descr in doc.arg_descrs: 
339                      if isinstance(arg, basestring): 
340                          args_with_descr.append(arg) 
341                      else: 
342                          args_with_descr += arg 
343                  for posarg in doc.posargs: 
344                      if (self._checks & DocChecker.DESCR and 
345                          posarg not in args_with_descr): 
346                          self.warning('Argument(s) not described', doc) 
347                      if (self._checks & DocChecker.TYPE and 
348                          posarg not in doc.arg_types): 
349                          self.warning('Argument type(s) not described', doc) 
 350   
352          self._warnings.setdefault(msg,set()).add(doc) 
 353