Changeset 83
- Timestamp:
- 07/09/06 13:05:49 (7 years ago)
- Files:
-
- branches/mk/cheesecake/cheesecake_index.py (modified) (7 diffs)
- branches/mk/cheesecake/codeparser.py (modified) (1 diff)
- branches/mk/cheesecake/model.py (modified) (13 diffs)
- branches/mk/tests/unit/test_index_unittests.py (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/mk/cheesecake/cheesecake_index.py
r82 r83 52 52 return new_list 53 53 54 if 'set' not in dir(__builtins__): 55 from sets import Set as set 56 54 57 def isiterable(obj): 55 58 """Check whether object is iterable. … … 111 114 if dir in ['test', 'tests']: 112 115 return 'test' 113 elif dir in ['doc s', 'demo', 'example']:116 elif dir in ['doc', 'docs', 'demo', 'example', 'examples']: 114 117 return 'demo' 115 118 return 'module' … … 788 791 max_value = 50 789 792 790 def compute(self, files_list, functions, package_dir):793 def compute(self, files_list, functions, classes, package_dir): 791 794 unittest_cnt = 0 792 self.functions_tested = {} 793 795 functions_tested = set() 796 797 # Gather all function names called from test files. 794 798 for testfile in get_files_of_type(files_list, 'test'): 795 799 fullpath = os.path.join(package_dir, testfile) 796 800 code = CodeParser(fullpath, self.cheesecake.log.debug) 797 801 798 func_called = code.functions_called() 799 800 for func in func_called: 801 self.functions_tested[func] = 1 802 803 for funcname in functions: 804 if self.is_unit_tested(funcname): 802 functions_tested = functions_tested.union(code.functions_called) 803 804 for name in functions + classes: 805 if name in functions_tested: 805 806 unittest_cnt += 1 806 self.log.cheesecake.debug("%s is unit tested" % funcname) 807 807 self.cheesecake.log.debug("%s is unit tested" % name) 808 809 functions_classes_cnt = len(functions) + len(classes) 808 810 percent = 0 809 if len(functions)> 0:810 percent = float(unittest_cnt)/float( len(functions))811 if functions_classes_cnt > 0: 812 percent = float(unittest_cnt)/float(functions_classes_cnt) 811 813 812 814 # Scale the result. 813 815 self.value = int(ceil(percent * self.max_value)) 814 816 815 self.details = "found %d/%d=%.2f%% unit tested methods/functions." %\816 (unittest_cnt, len(functions), percent*100)817 self.details = "found %d/%d=%.2f%% unit tested classes/methods/functions." %\ 818 (unittest_cnt, functions_classes_cnt, percent*100) 817 819 818 820 return self.value 819 820 def is_unit_tested(self, funcname):821 elem = funcname.split(".")822 n1 = elem[-1]823 n2 = ""824 if len(elem) > 1:825 n2 = elem[-2] + "." + elem[-1]826 for key in self.functions_tested.keys():827 if key.startswith(n1) or (n2 and key.startswith(n2)):828 return True829 return False830 821 831 822 class IndexPyLint(Index): … … 893 884 subindices = [ 894 885 IndexPyLint, 895 #IndexUnitTests, TODO886 IndexUnitTests, 896 887 ] 897 888 … … 1299 1290 functions : list 1300 1291 List of all functions defined in package sources. 1292 classes : list 1293 List of all classes defined in package sources. 1301 1294 object_cnt : int 1302 1295 Number of documentable objects found in all package modules. … … 1312 1305 self.docformat_cnt = 0 1313 1306 self.functions = [] 1307 self.classes = [] 1314 1308 1315 1309 # Parse all application files and count objects … … 1323 1317 self.docformat_cnt += code.formatted_docstrings_count 1324 1318 self.functions += code.functions 1319 self.classes += code.classes 1325 1320 1326 1321 # Log a bit of debugging info. branches/mk/cheesecake/codeparser.py
r44 r83 187 187 return len(self.docstrings_by_format[type]) 188 188 189 def functions_called(self):189 def _functions_called(self): 190 190 """Return list of functions called by functions/methods 191 191 defined in this module. 192 192 """ 193 193 return self.system.func_called.keys() 194 195 functions_called = property(_functions_called) branches/mk/cheesecake/model.py
r40 r83 1 """ 2 Code borrowed from Michael Hudson's docextractor package with the author's 3 permission. 4 5 The original code is available at http://codespeak.net/svn/user/mwh/docextractor/. 6 7 Changes: 8 * do not print warnings to stdout (in System.warning) 9 * collect all function calls 10 """ 11 12 1 13 from compiler import ast 2 14 import sys … … 10 22 11 23 import ast_pp 24 25 26 def get_call_name(node): 27 assert isinstance(node, ast.CallFunc) 28 29 def get_name(node): 30 if isinstance(node, ast.Name): 31 return node.name 32 elif isinstance(node, str): 33 return node 34 elif isinstance(node, tuple): 35 if len(node) == 1: 36 return node[0] 37 else: 38 return "%s.%s" % (get_name(node[:-1][0]), node[-1]) 39 elif isinstance(node, ast.Getattr): 40 return get_name(node.asList()) 41 else: 42 raise TypeError("Bad function name type: %s." % node) 43 44 return get_name(node.node) 45 46 def get_function_calls(node, fc): 47 if not isinstance(node, ast.Node): 48 return 49 50 for child in node.getChildren(): 51 if isinstance(child, ast.CallFunc): 52 func_called = get_call_name(child) 53 fc[func_called] = 1 54 55 get_function_calls(child, fc) 56 12 57 13 58 class Documentable(object): … … 50 95 obj = system.allobjects[parts[0]] 51 96 break 52 if verbose: 53 print "1 didn't find %r from %r"%(dottedname, 97 for othersys in system.moresystems: 98 if parts[0] in othersys.allobjects: 99 obj = othersys.allobjects[parts[0]] 100 break 101 else: 102 if verbose: 103 print "1 didn't find %r from %r"%(dottedname, 54 104 self.fullName()) 55 return None 105 return None 106 break 56 107 else: 57 108 fn = obj._name2fullname[parts[0]] … … 171 222 assert m.docstring is None 172 223 m.docstring = node.doc 173 self.system.push(m )224 self.system.push(m, node) 174 225 self.default(node) 175 226 self.system.pop(m) … … 179 230 if roots: 180 231 mod, = roots 181 self.system.push(mod )232 self.system.push(mod, node) 182 233 self.default(node) 183 234 self.system.pop(mod) … … 244 295 245 296 def visitFunction(self, node): 246 func = self.system.pushFunction(node.name, node.doc) 297 fc = {} 298 get_function_calls(node, fc) 299 func = self.system.pushFunction(node.name, node.doc, fc) 247 300 if node.lineno is not None: 248 301 func.linenumber = node.lineno … … 304 357 # for import * statements 305 358 self.importstargraph = {} 359 self.func_called = {} 306 360 self.state = 'blank' 307 361 self.packages = [] 362 self.moresystems = [] 363 self.urlprefix = '' 308 364 309 365 def _push(self, cls, name, docstring): … … 365 421 self.current = self.current.parent 366 422 367 def push(self, obj ):423 def push(self, obj, node=None): 368 424 self._stack.append(self.current) 369 425 self.current = obj … … 383 439 self._pop(self.Module) 384 440 385 def pushFunction(self, name, docstring): 441 def pushFunction(self, name, docstring, func_called): 442 self.func_called.update(func_called) 386 443 return self._push(self.Function, name, docstring) 387 444 def popFunction(self): … … 431 488 else: 432 489 fn = '<None>' 433 #print fn, type, detail434 490 self.warnings.setdefault(type, []).append((fn, detail)) 435 491 … … 444 500 def recordBasesAndSubclasses(self): 445 501 for cls in self.objectsOfType(Class): 446 for n in cls. rawbases:502 for n in cls.bases: 447 503 o = cls.parent.resolveDottedName(n) 448 504 cls.baseobjects.append(o) … … 450 506 o.subclasses.append(cls) 451 507 508 def __getstate__(self): 509 state = self.__dict__.copy() 510 del state['moresystems'] 511 return state 512 452 513 def __setstate__(self, state): 514 self.moresystems = [] 453 515 # this is so very, very evil. 454 516 # see doc/extreme-pickling-pain.txt for more. … … 512 574 while mv.morenodes: 513 575 obj, node = mv.morenodes.pop(0) 514 system.push(obj )576 system.push(obj, node) 515 577 mv.visit(node) 516 578 system.pop(obj)
