| # -*- coding: GBK -*-    | 
| #write:zfl  | 
| #  | 
| ##@package PyTrackObj.py  | 
| # Ä£¿éµÄ¼òҪ˵Ã÷:´úÂëÖ´ÐÐÂÊ×·×ÙÄÚ²¿´¢´æÀà  | 
| # @author:zfl  | 
| # @date 2010-07-21 11:00  | 
| # @version 1.4  | 
| #  | 
| # ÐÞ¸Äʱ¼ä ÐÞ¸ÄÈË ÐÞ¸ÄÄÚÈÝ  | 
| # @change: "2010-07-21 11:00" zfl ÐÂÔö½Ó¿Ú£¬¿É»ñµÃºÍÉèÖÃPyObjÀà¡¢FuncObjÀàÐÅÏ¢  | 
| # @change: "2010-08-03 11:00" zfl ÐÂÔö½Ó¿Ú£¬¿É»ñµÃºÍÉèÖÃPyObjÀà¡¢FuncObjÀàÐÅÏ¢  | 
| # @change: "2010-08-18 16:00" zfl ÐÂÔö½Ó¿Ú  | 
| # @change: "2010-11-03 10:00" zfl ÐÂÔöµ¥ÐÐÀ¨ºÅµÄÅÐ¶Ï  | 
| #  | 
| # Ä£¿éÏêϸ˵Ã÷:´úÂëÖ´ÐÐÂÊ×·×ÙÄÚ²¿´¢´æÀà  | 
| #  | 
| #-------------------------------------------------------------------------------  | 
|   | 
| """Version = 2010-11-03 10:00"""  | 
|   | 
| #-------------------------------------------------------------------------------  | 
| #µ¼Èë  | 
| import os  | 
| import time  | 
| import md5  | 
| import traceback  | 
|   | 
| #-------------------------------------------------------------------------------  | 
| #È«¾Ö±äÁ¿  | 
|   | 
| FORM_NAME = "PyTrackObj"  | 
|   | 
| IGNORE_FUNC_LIST = []  | 
|   | 
| FILE_TRACK_MODE = 1  # Îļþ×·×Ùģʽ  | 
| FUNC_TRACK_MODE = 2  # º¯Êý×·×Ùģʽ  | 
|   | 
| UI_OUTPUT_MODE = 0  # ½çÃæÊä³öģʽ  | 
| FILE_OUTPUT_MODE = 1  # ÎļþÊä³öģʽ  | 
|   | 
| #---µ÷ÊÔº¯Êý---------------------------------------------------------------------  | 
|   | 
| NOW_TIME = 'log%s%s%s%s%s%s.txt'%tuple(['%02d'%time.localtime()[i] for i in range(6)])  | 
|   | 
| LOG_PATH = os.getcwd() + "\\log\\"      # log·¾¶  | 
|   | 
| ## Ð´logº¯Êý  | 
| #  @param *varlist ²»¶¨²Î  | 
| #  @return ÎÞ·µ»ØÖµ  | 
| #  @remarks ½«´«ÈëµÄlogÐÅϢдÈëÖ¸¶¨logÎļþ  | 
| def LogEx(*varlist):  | 
|     info = '[%s%s%s%s%s%s]'%tuple(['%02d'%time.localtime()[i] for i in range(6)])  | 
|     for i in range(1, len(varlist)):  | 
|         curValue = varlist[i]  | 
|         info += "( "+str(type(curValue)) + ":" + str(curValue) + " ),"  | 
|       | 
|     if not os.path.isdir(LOG_PATH):  | 
|         os.mkdir(LOG_PATH)  | 
|           | 
|     if os.path.isfile(LOG_PATH +  NOW_TIME):  | 
|         logfile = open(LOG_PATH +  NOW_TIME, 'a')  | 
|     else:  | 
|         logfile = file(LOG_PATH +  NOW_TIME, 'w')  | 
|           | 
|     logfile.write('\t'*int(varlist[0])+info+'\n')  | 
|     logfile.close()  | 
|       | 
| LogEx(0, "CurPath=%s"%os.getcwd())  | 
|      | 
|           | 
| ## ÔÚÖ¸¶¨Ä¿Â¼Ï£¬²éÕÒÎļþ£¬²¢·µ»ØÂ·¾¶  | 
| #  @param path£ºÂ·¾¶  | 
| #  @param filename£ºÎļþÃû  | 
| #  @return ÕÒµ½·µ»ØÂ·¾¶£¬Ã»ÕÒµ½·µ»Ø¿Õ´®  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷£ºÔÚÖ¸¶¨Ä¿Â¼Ï£¬²éÕÒÎļþ£¬²¢·µ»ØÂ·¾¶  | 
| def GetFilePath(path, filename):  | 
|      | 
|     for dir in os.listdir(path):  | 
|         curPath = path + "\\"  + dir  | 
|           | 
|         # ÊÇÎļþ  | 
|         if os.path.isfile(curPath):  | 
|             # ÕÒµ½  | 
|             if dir == filename:  | 
| #                LogEx(2, "%s : GetFilePath = %s"%(filename, path))  | 
|                 return path   | 
|                   | 
|         # ÊÇÎļþ¼Ð  | 
|         if os.path.isdir(curPath):  | 
|             tempPath = GetFilePath(curPath, filename)  | 
|             if tempPath != "":  | 
|                 return tempPath  | 
|             continue  | 
|               | 
|     return ""  | 
|   | 
|   | 
| ## Ö¸¶¨×Ö·ûÁбí²ð·Ö×Ö·û´®  | 
| #  @param line: ÐèÒª²ð·ÖµÄ×Ö·û´®  | 
| #  @param charList: ×Ö·ûÁÐ±í  | 
| #  @return ·µ»Ø²ð³öµÄµÚÒ»¸ö×Ó´®  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
| def GetSplitFirstByChar(line, charList):  | 
|       | 
|     for i in range(len(line)):  | 
|         if line[i] in charList:  | 
|             return line[:i]  | 
|       | 
|     return line  | 
|   | 
|   | 
| ## ÅжÏÖ¸¶¨ÐÐÄÚÈÝÊÇ·ñ¿ÉÒÔºöÂÔ  | 
| #  @param rowContent: ÐÐÄÚÈÝ  | 
| #  @return ÊÇ·ñ¿ÉÒÔºöÂÔ  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
| def IsLineNeedIgnore(rowContent):  | 
|       | 
|     rowContent = rowContent.split("#")[0].strip()  | 
|     # ºöÂÔµ¥ÐÐÀ¨ºÅ  | 
|     if rowContent in ["(", "[", "{"]:  | 
|         return True  | 
|       | 
|     # ºöÂÔµ¥ÐÐÀ¨ºÅ  | 
|     if rowContent.startswith(")") or rowContent.startswith("]") or rowContent.startswith("}"):  | 
|         return True  | 
|       | 
|     charList = [" ", "\t", "\n"]  | 
|       | 
|     # ²ð·Ö×Ö·û´®  | 
|     rowContent = GetSplitFirstByChar(rowContent, charList)  | 
|       | 
|     # ºöÂÔglobal  | 
|     if rowContent == 'global':  | 
|         return True  | 
|           | 
| #    # ºöÂÔreturn  | 
| #    if rowContent == 'return':  | 
| #        return True  | 
|   | 
|     # ºöÂÔbreak  | 
|     if rowContent == 'break':  | 
|         return True  | 
|       | 
|     # ºöÂÔelse  | 
|     if rowContent == 'else:':  | 
|         return True  | 
|           | 
|     # ºöÂÔpass  | 
|     if rowContent == 'pass':  | 
|             return True  | 
|       | 
|     # ÎÞÐèºöÂÔµÄÄÚÈÝ      | 
|     return False  | 
|   | 
|   | 
| ## ¶Ôº¯Êý¶ÔÏóµÄÅÅÐò±È½Ïº¯Êý  | 
| #  @param x: ºóÒ»¸ö  | 
| #  @param y: Ç°Ò»¸ö  | 
| #  @return Ð¡ÓÚ£¬µÈÓÚ£¬´óÓÚ£º-1£¬ 0 £¬1  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
| def FuncObjCmp(x, y):  | 
|       | 
|     if x.startIndex > y.startIndex:  | 
|         return 1  | 
|     elif x.startIndex < y.startIndex:  | 
|         return -1  | 
|     else:  | 
|         return 0  | 
|   | 
|           | 
| ## Éú³Éº¯ÊýµÄMD5  | 
| #  @param contenListt: ´úÂëÄÚÈÝ  | 
| #  @param execRowList: ¿ÉÖ´ÐÐÐÐÄÚÈÝ  | 
| #  @param MD5Key: MD5ÃÜÔ¿  | 
| #  @return ·µ»ØMD5  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷£ºÉú³Éº¯ÊýµÄMD5  | 
| def CalcFuncMD5(contentList, execRowList, MD5Key):  | 
|     mdstr = ""  | 
|   | 
|     # ºÏ³ÉÑéÖ¤×Ö·û´®  | 
|     for rowInfo in execRowList:  | 
|         if rowInfo[2] < 2:  | 
|             mdstr += contentList[rowInfo[0]-1].rstrip(" ")  | 
|               | 
|     # ·µ»ØÉú³ÉµÄMD5  | 
|     return md5.md5(mdstr + MD5Key).hexdigest()  | 
|   | 
|        | 
| ## ×Ö·û´®ÄÚÈÝÉú³ÉµÄMD5  | 
| #  @param reportString: ÄÚÈÝ×Ö·û´®  | 
| #  @param MD5Key: MD5ÃÜÔ¿  | 
| #  @return ·µ»ØMD5  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷£ºÉú³ÉµÄMD5  | 
| def CalcStringMD5(reportString, MD5Key):  | 
|       | 
|     contentList = reportString.split("\r\n")  | 
|           | 
|     # ·µ»ØÉú³ÉµÄMD5  | 
|     return CalcListMD5(contentList, MD5Key)  | 
|   | 
| #t =""  | 
|   | 
| ## ÁбíÄÚÈÝÉú³ÉµÄMD5  | 
| #  @param reportList: ÄÚÈÝÁÐ±í  | 
| #  @param MD5Key: MD5ÃÜÔ¿  | 
| #  @return ·µ»ØMD5  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷£ºÉú³ÉµÄMD  | 
| def CalcListMD5(reportList, MD5Key):  | 
| #    global t  | 
|       | 
|     mdstr = ""  | 
|     # ºÏ³ÉÑéÖ¤×Ö·û´®  | 
|     for line in reportList:  | 
|         line = line.replace("\n", "")  | 
|         mdstr += line.replace("\r", "")  | 
|     | 
| #     ·µ»ØÉú³ÉµÄMD5  | 
|     return md5.md5(mdstr + MD5Key).hexdigest()  | 
|   | 
|   | 
| ## pyÎļþÀà  | 
| #  | 
| # ±»Ö´Ðе½µÄpyµÄ¹ÜÀíÀà  | 
| class PyObj:  | 
|       | 
|     ## ¹¹Ô캯Êý  | 
|     #  @param pyName: PyÎļþÃû  | 
|     #  @param MD5Key£ºMD5ÃÜÔ¿  | 
|     #  @param scriptPath£ºPy·¾¶  | 
|     #  @param isCreate: ÊÇ·ñ¸ù¾ÝPYÉú³ÉPyObj  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
|     def __init__(self, pyName, MD5Key="", scriptPath="", isCreate=True):  | 
|         self.pyName = pyName         # pyÃû  | 
|         self.funcObjList = []        # º¯Êý¶ÔÏóÁÐ±í  | 
|         self.contentList = []        # pyÄÚÈÝÁÐ±í  | 
|         self.pyExecCount = 0         # pyÒÑÖ´ÐÐÐÐÊý  | 
|         self.pyTotalCount = 0        # py×ÜÓÐЧÐÐÊý  | 
|         self.isPyFileExist = True    # Ãû×Ö¶ÔÓ¦µÄpyÎļþÊÇ·ñ´æÔÚ  | 
|         self.isTracking = False      # ÊÇ·ñÊÇ×·×ÙÖÐ  | 
|         self.MD5 = ""                # PyÎļþMD5  | 
|         self.MD5Key = MD5Key         # MD5ÃÜÔ¿  | 
|   | 
|         if isCreate:  | 
|             self.CreateFuncObj(scriptPath)         # ½âÎöPyÎļþÐÅÏ¢  | 
|       | 
|       | 
|     ## Éú³Éº¯Êý¶ÔÏóÁÐ±í    | 
|     #  @param scriptPath£ºPy·¾¶  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
|     def CreateFuncObj(self, scriptPath):  | 
| #        LogEx(0, "CreateFuncObj(self)")  | 
|           | 
|         tempPath = GetFilePath(scriptPath, self.pyName)  | 
|         # pyÃû¶ÔÓ¦µÄÎļþ²»´æÔÚ  | 
|         if tempPath == "":  | 
|             LogEx(1, "self.isPyFileExist = False", scriptPath, self.pyName)  | 
|             self.isPyFileExist = False  | 
|             return  | 
|           | 
|         # ¶ÁÈ¡Îļþ  | 
|         file = open(tempPath + "\\" + self.pyName, 'r')  | 
|         self.contentList = file.readlines()  | 
|         file.close()  | 
|           | 
|         isFindFuncHead = False      # ÊÇ·ñÕÒµ½º¯ÊýÍ·  | 
|         isFindClassHead = False     # ÊÇ·ñÕÒµ½ÀàÍ·  | 
|         isFindingComment = False    # ÊÇ·ñÕÒµ½Àà»òº¯Êý×¢ÊÍ  | 
|         startIndex = 0              # º¯ÊýÍ·µÄÆðʼλÖà  | 
|         funcName = ""               # ÕÒµ½µÄº¯ÊýÃû  | 
|         className = ""              # ÕÒµ½µÄÀàÃû  | 
|         funcComment = ""            # º¯Êý×¢ÊÍ  | 
|         rowCount = 0            # º¯Êý×ÜÐÐÊý  | 
|         rowList = []            # º¯ÊýÐÐÐÅÏ¢ÁÐ±í  | 
|         rowStartIndex = 0       # º¯ÊýÐÐÆðʼ  | 
|         rowEndIndex = 0         # º¯ÊýÐнáÊø  | 
|           | 
|         contentList = self.contentList  | 
|         #±éÀúÿÐÐ  | 
|         for i in range(len(contentList)+1):  | 
| #            print i+1,":",contentList[i]  | 
|               | 
|             # Îļþ½áÊø  | 
|             if i == len(contentList):  | 
|                 if isFindFuncHead:  | 
|                     # »ñµÃº¯Êý×¢ÊÍ  | 
|                     for j in range(rowStartIndex-2, 0, -1):  | 
|                         if contentList[j].lstrip().startswith("##"):  | 
|                             funcComment = contentList[j]  | 
| #                            isFindingComment = True           # ÕÒµ½º¯Êý×¢ÊÍ  | 
|                             break  | 
|                         if not contentList[j].lstrip().startswith("#"):  | 
|                             break  | 
|                     isFindFuncHead = False    | 
|                     startIndex = 0  | 
|                       | 
|                     # ½«º¯ÊýÐÐÊý¼ÓÖÁpy×ÜÐÐÊý  | 
|                     self.pyTotalCount += rowCount  | 
|                     # ´´½¨º¯Êý¶ÔÏó  | 
| #                    LogEx(2, "findFunc=" + funcName)  | 
|                           | 
|                     # Éú³Éº¯Êýmd5  | 
|                     MD5 = CalcFuncMD5(contentList, rowList, self.MD5Key)  | 
|                     tempFuncObj = FuncObj(className, funcName, funcComment, rowList, rowStartIndex, rowEndIndex, MD5)  | 
|                     self.funcObjList.append(tempFuncObj)  # ½«º¯Êý¶ÔÏó¼ÓÖÁÁÐ±í  | 
|                     funcName = ''      # ÖØÖú¯ÊýÃû  | 
|                     rowCount = 0       # ÖØÖÃ×ÜÐÐÊý  | 
|                     rowList = []       # ÖØÖÃÐÐÄÚÈÝÁÐ±í  | 
|                     funcComment = ''   # ÖØÖú¯Êý×¢ÊÍ  | 
|                     rowStartIndex = 0  # ÖØÖú¯ÊýÐÐÆðʼ   | 
|                     rowEndIndex = 0    # ÖØÖú¯ÊýÐнáÊø  | 
|                     isFindingComment = False  | 
|                   | 
|                 break  | 
|               | 
|             # ÕÒµ½Àà»òº¯Êý×¢ÊÍ  | 
|             if contentList[i].strip().startswith("##"):  | 
|                 rowList.append([i + 1, i + 1 - rowStartIndex, 2, contentList[i]])  # ±£´æÐÐÐÅÏ¢  | 
|                 continue  | 
|               | 
|             # Çå³ýÊ×β¿ØÖÆ·ûºóµÄÐÐÄÚÈÝ  | 
|             temp = contentList[i].strip()  | 
|               | 
|             # ´¦Àí·ÖÐк÷û"\"  | 
|             if temp.endswith("\\"):  | 
|                 contentList[i] = contentList[i][:contentList[i].rfind("\\")] + " " + contentList[i + 1].lstrip()  | 
|                 contentList[i + 1] = "\n"  | 
|                 temp = contentList[i].strip()  | 
|                   | 
|             # ¿ÕÐÐ  | 
|             if len(temp) == 0:  | 
|                 if isFindFuncHead:  | 
|                     rowList.append([i + 1, i + 1 - rowStartIndex, 3, "\n"])  # ±£´æ¿ÕÐÐ  | 
|                 continue  | 
|               | 
|             # ÐÐ×¢ÊÍ  | 
|             if temp.startswith("#"):  | 
|                 rowList.append([i + 1, i + 1 - rowStartIndex, 2, contentList[i]])  # ±£´æÐÐÐÅÏ¢  | 
|                 continue  | 
|               | 
|             # ÕÒµ½º¯ÊýÍ·  | 
|             if temp.startswith("def "):  | 
|                 # »ñµÃº¯Êý×¢ÊÍ  | 
|                 for j in range(rowStartIndex-2, 0, -1):  | 
|                     if contentList[j].lstrip().startswith("##"):  | 
|                         funcComment = contentList[j]  | 
| #                        isFindingComment = True           # ÕÒµ½º¯Êý×¢ÊÍ  | 
|                         break  | 
|                     if not contentList[j].lstrip().startswith("#"):  | 
|                         break  | 
|                       | 
|                 if isFindFuncHead:  | 
|                     startIndex = 0  | 
|                       | 
|                     # ½«º¯ÊýÐÐÊý¼ÓÖÁpy×ÜÐÐÊý  | 
|                     self.pyTotalCount += rowCount  | 
|                     # ´´½¨º¯Êý¶ÔÏó  | 
| #                    LogEx(2, "findFunc=" + funcName)  | 
|                           | 
|                     # Éú³Éº¯Êýmd5  | 
|                     MD5 = CalcFuncMD5(contentList, rowList, self.MD5Key)  | 
|                     tempFuncObj = FuncObj(className, funcName, funcComment, rowList, rowStartIndex, rowEndIndex, MD5)  | 
|                     self.funcObjList.append(tempFuncObj)  # ½«º¯Êý¶ÔÏó¼ÓÖÁÁÐ±í  | 
|                     funcName = ''      # ÖØÖú¯ÊýÃû  | 
|                     rowCount = 0       # ÖØÖÃ×ÜÐÐÊý  | 
|                     rowList = []       # ÖØÖÃÐÐÄÚÈÝÁÐ±í  | 
|                     funcComment = ''   # ÖØÖú¯Êý×¢ÊÍ  | 
|                     rowStartIndex = 0  # ÖØÖú¯ÊýÐÐÆðʼ  | 
|                     rowEndIndex = 0    # ÖØÖú¯ÊýÐнáÊø  | 
|                     isFindingComment = False  | 
|                       | 
| #                if isFindingComment == False:  | 
| #                    LogEx(1, "No Comment!!!")  | 
|                       | 
|                 endIndex = temp.find('(')                # º¯ÊýÃû½áβË÷Òý  | 
|                 if temp[4:endIndex] in IGNORE_FUNC_LIST:  | 
|                     continue  | 
|                 isFindFuncHead = True                     # ÒÑÕÒµ½º¯ÊýÍ·  | 
|                 rowStartIndex = i + 1                     # º¯ÊýÐÐÆðʼ  | 
|                 startIndex = contentList[i].find('def')   # º¯ÊýÍ·µÄÆðʼλÖà  | 
|                   | 
|                 if startIndex == 0:  | 
|                     isFindClassHead = False               # ÀඨÒå½áÊø  | 
|                     className = ""                        # Çå¿ÕÀàÃû  | 
|                       | 
|                 funcName = temp[4:endIndex]               # º¯ÊýÃû  | 
|                 continue  | 
|   | 
|             # ÕÒµ½ÀàÍ·  | 
|             if contentList[i].startswith("class "):  | 
|                 if isFindFuncHead:  | 
|                     isFindFuncHead = False  | 
|                     startIndex = 0  | 
|                       | 
|                     # ½«º¯ÊýÐÐÊý¼ÓÖÁpy×ÜÐÐÊý  | 
|                     self.pyTotalCount += rowCount  | 
|                     # ´´½¨º¯Êý¶ÔÏó  | 
| #                    LogEx(2, "findFunc=" + funcName)  | 
|                     # »ñµÃº¯Êý×¢ÊÍ  | 
|                     for j in range(rowStartIndex-2, 0, -1):  | 
|                         if contentList[j].startswith("## "):  | 
|                             funcComment = contentList[j]  | 
|                         if not contentList[j].startswith("#"):  | 
|                             break  | 
|                           | 
|                     # Éú³Éº¯Êýmd5  | 
|                     MD5 = CalcFuncMD5(contentList, rowList, self.MD5Key)  | 
|                     tempFuncObj = FuncObj(className, funcName, funcComment, rowList, rowStartIndex, rowEndIndex, MD5)  | 
|                     self.funcObjList.append(tempFuncObj)  # ½«º¯Êý¶ÔÏó¼ÓÖÁÁÐ±í  | 
|                     funcName = ''      # ÖØÖú¯ÊýÃû  | 
|                     rowCount = 0       # ÖØÖÃ×ÜÐÐÊý  | 
|                     rowList = []       # ÖØÖÃÐÐÄÚÈÝÁÐ±í  | 
|                     funcComment = ''   # ÖØÖú¯Êý×¢ÊÍ  | 
|                     rowStartIndex = 0  # ÖØÖú¯ÊýÐÐÆðʼ  | 
|                     rowEndIndex = 0    # ÖØÖú¯ÊýÐнáÊø  | 
|                     isFindingComment = False  | 
|                       | 
| #                if isFindingComment == False:  | 
| #                    LogEx(1, "No Comment!!!")  | 
|                       | 
|                 isFindClassHead = True                    # ÒÑÕÒµ½ÀàÍ·  | 
|                 endIndex = temp.find(":")                 # ÀàÃû½áβË÷Òý  | 
|                 className = temp[6:endIndex]              # ÀàÃû  | 
|                 continue  | 
|               | 
|             # ÒÑÕÒµ½º¯Êý¶¨Òå´¦  | 
|             if isFindFuncHead:  | 
|                 # µÚÒ»¸ö·Ç¿Õ×Ö·ûµÄË÷Òý<=±Èº¯ÊýÍ·µÄË÷ÒýС¡ª¡ªÒѵ½±¾º¯Êý½áβ  | 
|                 if contentList[i].find(temp[0]) <= startIndex:  | 
|                     isFindFuncHead = False    | 
|                     startIndex = 0  | 
|                       | 
|                     # ½«º¯ÊýÐÐÊý¼ÓÖÁpy×ÜÐÐÊý  | 
|                     self.pyTotalCount += rowCount  | 
|                     # ´´½¨º¯Êý¶ÔÏó  | 
| #                    LogEx(2, "findFunc=" + funcName)  | 
|                     # »ñµÃº¯Êý×¢ÊÍ  | 
|                     for j in range(rowStartIndex-2, 0, -1):  | 
|                         if contentList[j].startswith("## "):  | 
|                             funcComment = contentList[j]  | 
|                         if not contentList[j].startswith("#"):  | 
|                             break  | 
|                           | 
|                     # Éú³Éº¯Êýmd5  | 
|                     MD5 = CalcFuncMD5(contentList, rowList, self.MD5Key)  | 
|                     tempFuncObj = FuncObj(className, funcName, funcComment, rowList, rowStartIndex, rowEndIndex, MD5)  | 
|                     self.funcObjList.append(tempFuncObj)  # ½«º¯Êý¶ÔÏó¼ÓÖÁÁÐ±í  | 
|                     funcName = ''      # ÖØÖú¯ÊýÃû  | 
|                     rowCount = 0       # ÖØÖÃ×ÜÐÐÊý  | 
|                     rowList = []       # ÖØÖÃÐÐÄÚÈÝÁÐ±í  | 
|                     funcComment = ''   # ÖØÖú¯Êý×¢ÊÍ  | 
|                     rowStartIndex = 0  # ÖØÖú¯ÊýÐÐÆðʼ  | 
|                     rowEndIndex = 0    # ÖØÖú¯ÊýÐнáÊø  | 
|                     isFindingComment = False  | 
|                       | 
|                 # Î´µ½º¯Êýµ×  | 
|                 else:  | 
|                     if isFindClassHead and not isFindFuncHead:  | 
|                         continue  | 
|                       | 
|                     rowEndIndex = i + 1    # º¯ÊýÐнáÊø  | 
|                       | 
|                     if IsLineNeedIgnore(temp):  # ÊÇ·ñÐèÒªºöÂÔ±¾ÐÐ  | 
|                         rowList.append([i + 1, i + 1 - rowStartIndex, 2, contentList[i]])  # ±£´æÐÐÐÅÏ¢  | 
|                         continue  | 
|                       | 
|                     rowCount += 1      # ×ÜÐÐÊý+1  | 
|                     rowList.append([i + 1, i + 1 - rowStartIndex, 0, contentList[i]])  # ±£´æÐÐÐÅÏ¢  | 
|       | 
|       | 
|     ## ²éѯº¯ÊýÊÇ·ñÒÑÔÚº¯Êý¶ÔÏóÁбíÖÐ  | 
|     #  @param funcName:º¯ÊýÃû  | 
|     #  @param className:º¯ÊýËùÊôÀàÃû  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º²éѯ´«²ÎµÄº¯ÊýÃûËùÖ¸º¯ÊýÊÇ·ñÒÑÔÚº¯Êý¶ÔÏóÁбíÖУ¬ÊÇ·µ»Ø¸ÃfuncObj£¬²»ÔÚ·µ»ØNone  | 
|     def FindFuncObj(self, funcName, className=""):  | 
|           | 
|         for funcObj in self.funcObjList:  | 
|             if funcName == funcObj.funcName:  | 
|                 if className and funcObj.className != className:  | 
|                     continue  | 
|                 # ÕÒµ½£¬²¢·µ»Ø  | 
|                 return funcObj  | 
|           | 
|         # Î´ÕÒµ½£¬·µ»ØNone  | 
|         return None           | 
|       | 
|       | 
|     ## ¸üк¯Êý״̬  | 
|     #  @param funcName:º¯ÊýÃû  | 
|     #  @param rowInfo:ÐÐÐÅÏ¢  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
|     def UpdateFuncState(self, funcName, rowIndex, returnValue):  | 
| #        print 'funcName:%s rowIndex:%s returnValue%s'%(funcName, rowIndex, returnValue)  | 
|           | 
|         tempFuncObj = self.FindFuncObj(funcName)  | 
|         if tempFuncObj:  | 
|             if tempFuncObj.UpdateRowState(rowIndex, returnValue):  | 
|                 self.pyExecCount += 1  | 
| #        else:  | 
| #            LogEx(0, 'py:%s has no FuncObj:%s'%(self.pyName,funcName))  | 
|                               | 
|                       | 
|     ## »ñµÃPyÃû  | 
|     #  @param ²ÎÊý  | 
|     #  @return PyÃû  | 
|     #  @remarks »ñµÃPyÃû  | 
|     def GetName(self):  | 
|           | 
|         return  self.pyName  | 
|       | 
|       | 
|     ## ÊÇ·ñ×·×ÙÖÐ  | 
|     #  @param ²ÎÊý  | 
|     #  @return ÊÇ·ñ×·×ÙÖÐ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º»ñµÃ×·×ÙÇé¿ö  | 
|     def IsTracking(self):  | 
|           | 
|         return self.isTracking  | 
|       | 
|           | 
|     ## ÉèÖÃ×·×Ù  | 
|     #  @param isTracking:zÊÇ·ñ×·×ÙÖÐ  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£ºÉèÖÃ×·×Ù  | 
|     def SetTrack(self, isTracking):  | 
|           | 
|         self.isTracking = isTracking    | 
|       | 
|           | 
|     ## ÉèÖú¯Êý×·×Ù  | 
|     #  @param isTracking:zÊÇ·ñ×·×ÙÖÐ  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£ºÉèÖÃ×·×Ù  | 
|     def SetAllFuncTrack(self, isTracking):  | 
|           | 
|         for funcObj in self.GetFuncObjList():  | 
|               | 
|             funcObj.SetTrack(isTracking)  | 
|               | 
|           | 
|     ## »ñÈ¡PyÐÅÏ¢  | 
|     #  @param ²ÎÊý  | 
|     #  @return PyÐÅÏ¢  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º±¾PyµÄÐÅÏ¢  | 
|     def GetPyInfo(self):  | 
|           | 
|         return (self.pyName,           # pyÃû  | 
|                 self.funcObjList,      # º¯Êý¶ÔÏóÁÐ±í  | 
|                 self.contentList,      # pyÄÚÈÝÁÐ±í  | 
|                 self.pyExecCount,      # pyÒÑÖ´ÐÐÐÐÊý  | 
|                 self.pyTotalCount,     # py×ÜÓÐЧÐÐÊý  | 
|                 self.isPyFileExist,    # Ãû×Ö¶ÔÓ¦µÄpyÎļþÊÇ·ñ´æÔÚ  | 
|                 self.isTracking,       # ÊÇ·ñÊÇ×·×ÙÖÐ  | 
|                 )  | 
|              | 
|               | 
|     ## »ñµÃº¯ÊýÃûÁÐ±í  | 
|     #  @param ²ÎÊý  | 
|     #  @return º¯ÊýÃûÁÐ±í  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º»ñµÃËùÓк¯ÊýµÄº¯ÊýÃûÁÐ±í  | 
|     def GetFuncNameList(self):  | 
|           | 
|         funcNameList = []  | 
|         for funcObj in self.funcObjList:  | 
|             funcNameList.append(funcObj.funcName)  | 
|               | 
|         return funcNameList  | 
|       | 
|       | 
|     ## »ñµÃº¯Êý¶ÔÏóÁÐ±í  | 
|     #  @param ²ÎÊý  | 
|     #  @return º¯Êý¶ÔÏóÁÐ±í  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º»ñµÃËùÓк¯ÊýµÄº¯Êý¶ÔÏóÁÐ±í  | 
|     def GetFuncObjList(self):  | 
|               | 
|         return self.funcObjList  | 
|       | 
|       | 
|     ## ÉèÖÃPyÐÅÏ¢  | 
|     #  @param pyName: pyÃû  | 
|     #  @param pyExecCount: pyÒÑÖ´ÐÐÐÐÊý  | 
|     #  @param pyTotalCount: py×ÜÓÐЧÐÐÊý  | 
|     #  @param funcObjList: º¯Êý¶ÔÏóÁÐ±í  | 
|     #  @param contentList: pyÄÚÈÝÁÐ±í  | 
|     #  @param MD5: PyÎļþMD5  | 
|     #  @param isPyFileExist: Ãû×Ö¶ÔÓ¦µÄpyÎļþÊÇ·ñ´æÔÚ  | 
|     #  @param isTracking: ÊÇ·ñÊÇ×·×ÙÖÐ  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£ºÉèÖÃPyµÄÐÅÏ¢  | 
|     def SetPyInfo(self, pyName, pyExecCount, pyTotalCount, funcObjList, contentList, \  | 
|                   MD5, isPyFileExist=True, isTracking=False):  | 
|           | 
|         self.pyName = pyName                 # pyÃû  | 
|         self.funcObjList = funcObjList       # º¯Êý¶ÔÏóÁÐ±í  | 
|         self.contentList = contentList       # pyÄÚÈÝÁÐ±í  | 
|         self.pyExecCount = pyExecCount       # pyÒÑÖ´ÐÐÐÐÊý  | 
|         self.pyTotalCount = pyTotalCount     # py×ÜÓÐЧÐÐÊý  | 
|         self.MD5 = MD5                       # PyÎļþMD5  | 
|         self.pyFileExist = isPyFileExist     # Ãû×Ö¶ÔÓ¦µÄpyÎļþÊÇ·ñ´æÔÚ  | 
|         self.isTracking = isTracking         # ÊÇ·ñÊÇ×·×ÙÖÐ  | 
|           | 
|           | 
|     ## ¼ÆËãPy¿ÉÖ´ÐÐÐÐÊý£¬ºÍ×ÜÐÐÊý  | 
|     #  @param ²ÎÊý  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º¼ÆËãPy¿ÉÖ´ÐÐÐÐÊý£¬ºÍ×ÜÐÐÊý  | 
|     def CalcFuncExecCount(self):  | 
|           | 
|         self.pyExecCount = 0                 # pyÒÑÖ´ÐÐÐÐÊý  | 
|         self.pyTotalCount = 0                # py×ÜÓÐЧÐÐÊý  | 
|           | 
|         for funcObj in self.funcObjList:  | 
|               | 
|             funcExecCount, funcTotalCount = funcObj.CalcRowExecCount()  | 
|             self.pyExecCount += funcExecCount   | 
|             self.pyTotalCount += funcTotalCount   | 
|               | 
|         return (self.pyExecCount, self.pyTotalCount)  | 
|               | 
|               | 
|     ## »ñµÃPyÖ´ÐÐÂÊ  | 
|     #  @param ²ÎÊý  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º»ñµÃPyÖ´ÐÐÂÊ  | 
|     def GetExecPercent(self):  | 
|           | 
|         if self.pyTotalCount == 0:  | 
|             return 0.0  | 
|         return  float(self.pyExecCount)/self.pyTotalCount*100  | 
|               | 
|               | 
|     ## »ñµÃPyÖ´ÐÐÐÐÊýÇé¿ö  | 
|     #  @param ²ÎÊý  | 
|     #  @return ·µ»ØÖµ (ÒÑÖ´ÐÐÐÐÊý£¬×ÜÐÐÊý)  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º»ñµÃPyÖ´ÐÐÐÐÊýÇé¿ö  | 
|     def GetExecRowCount(self):  | 
|            | 
|         return (self.pyExecCount, self.pyTotalCount)  | 
|       | 
|           | 
|     ## PyÖÐÐÂÔöº¯Êý¶ÔÏó  | 
|     #  @param funcObj: º¯Êý¶ÔÏó  | 
|     #  @param contentlist: Py´úÂë  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£ºPyÖÐÐÂÔöº¯Êý¶ÔÏó  | 
|     def AddFuncObj(self, funcObj):  | 
|           | 
|         if funcObj.funcName in self.GetFuncNameList():  | 
|             tempObj = self.FindFuncObj(funcObj.funcName, funcObj.className)  | 
|               | 
|             # MD5²»Í¬£¬²»ºÏ²¢  | 
|             if funcObj.GetMD5() != tempObj.GetMD5():  | 
|                 LogEx(1, '%s -> %s:MD5 Differ'%(self.pyName, funcObj.funcName))  | 
| #                print '%s -> %s:MD5 Differ'%(self.pyName, funcObj.funcName)  | 
| #                funcObj.MD5 = tempObj.GetMD5()  | 
|                 return  | 
|               | 
|             # Èç¹ûÓÐÏÈÇå³ý£¬ÔÙÌí¼Ó  | 
|             self.pyExecCount -= tempObj.execRowCount  | 
|             self.pyTotalCount -= tempObj.totalRowCount  | 
|               | 
|             # ¼Ç¼º¯ÊýÍ·ÐкŠ | 
|             funcStartIndex = tempObj.startIndex  | 
|             funcEndIndex = tempObj.endIndex  | 
|             isTracking = tempObj.isTracking  | 
|               | 
|             self.funcObjList.remove(tempObj)  | 
|               | 
|         else:  | 
|             funcStartIndex = funcObj.startIndex  | 
|             funcEndIndex = funcObj.endIndex  | 
|             isTracking = False  | 
|           | 
|         # º¯ÊýÍ·ÐкŲ»Í¬Ê±£¬ÒªÖØÐ¼ÆËãеĺ¯Êý¶ÔÏóµÄÿÐеÄÐкŠ | 
|         if funcStartIndex != funcObj.startIndex:  | 
|             funcObj.startIndex  | 
|             # ÐкÅÏà¶ÔÆ«ÒÆ  | 
|             offSet = funcObj.startIndex - funcStartIndex  | 
|             # ¼ÆËãÐкţ¬²¢Ìæ»»ÐÐ×Öµä  | 
|             tempRowObjDict = {}  | 
|             for rowObj in funcObj.rowObjDict.values():  | 
|                 rowInfoList = rowObj.GetRowInfo()  | 
|                 lineIndex = rowInfoList[0] - offSet  | 
|                 tempRowObjDict[lineIndex] = RowObj(lineIndex, rowInfoList[1], rowInfoList[2], rowInfoList[3])  | 
|                   | 
|             funcObj.rowObjDict = tempRowObjDict  | 
|           | 
|         funcObj.isTracking = isTracking  | 
|         funcObj.startIndex = funcStartIndex  | 
|         funcObj.endIndex = funcEndIndex  | 
|           | 
|         # ¼ÓÈëPy¶ÔÏó  | 
|         self.funcObjList.append(funcObj)   | 
|         self.pyExecCount += funcObj.execRowCount  | 
|         self.pyTotalCount += funcObj.totalRowCount  | 
|               | 
|         # ÖØÐÂÅÅÐò  | 
|         self.funcObjList.sort(FuncObjCmp)  | 
|           | 
|           | 
|     ##ºÏ²¢Py¶ÔÏó  | 
|     #  @param pyObj: Py¶ÔÏó  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£ººÏ²¢Py¶ÔÏó  | 
|     def AddPyObj(self, pyObj):  | 
|           | 
|         for funcObj in pyObj.funcObjList:  | 
|             tempFuncObj = self.FindFuncObj(funcObj.funcName, funcObj.className)  | 
|             if not tempFuncObj:  | 
|                 continue  | 
|             # ¸²¸ÇÂʸßÓÚµ±Ç°µÄ²ÅºÏ²¢  | 
|             if funcObj.GetExecPercent() > self.FindFuncObj(funcObj.funcName, funcObj.className).GetExecPercent():  | 
|                 self.AddFuncObj(funcObj)  | 
|           | 
|       | 
|     ## »ñÈ¡²âÊÔÐÅÏ¢  | 
|     #  @param funcName: º¯ÊýÃû  | 
|     #  @param trackMode: ×·×Ùģʽ£¬1 Îļþ¡¢2 º¯Êý  | 
|     #  @param showMode: Êä³öģʽ£¬0 ½çÃæ¡¢1 Îļþ  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º·µ»Ø´ËpyµÄ±»Ö´ÐÐÇé¿ö  | 
|     def GetTestReport(self, funcName, trackMode, outputMode):  | 
| #        LogEx(0, "GetTestReport(funcName=%s, trackMode=%d, outputMode=%d)"%(funcName, trackMode, outputMode))  | 
|           | 
|         # Îļþ²»´æÔÚ¡ª¡ª²âÊÔ±¨¸æ·µ»Ø´´½¨±¨¸æÊ§°Ü  | 
|         if not self.isPyFileExist:  | 
|             return '¡¾%s¡¿Create Report Fail\r\n'%self.pyName  | 
|           | 
|         tempReport = ""  | 
| #        self.pyExecCount = 0  | 
|         CRLF = "\r\n"  | 
|           | 
|         # µ¥º¯Êý±¨¸æ  | 
|         if funcName:  | 
|             funcObj = self.FindFuncObj(funcName)  | 
| #            LogEx(1, "funcObj.isTracking=%s"%funcObj.isTracking)  | 
|             if funcObj and (funcObj.isTracking or trackMode == FILE_TRACK_MODE):  | 
|                 # Ìí¼Óÿ¸öº¯Êý·µ»ØµÄ±¨¸æ  | 
|                 funcExecCount, tempReport = funcObj.GetFuncReport(self.contentList, outputMode)  | 
|                   | 
|         else:  | 
|             for funcObj in self.funcObjList:  | 
|     #            LogEx(1, "funcName=%s, %s, %s)"%(funcObj.funcName, self.isTracking, funcObj.isTracking))  | 
|                 # º¯Êý×·×Ùģʽ  | 
|                 if trackMode == FUNC_TRACK_MODE:  | 
|                     # Î´×·×ÙµÄpy  | 
|                     if not self.isTracking:  | 
|                         continue  | 
|                     # Î´×·×ٵĺ¯Êý  | 
|                     if not funcObj.isTracking:  | 
|                         continue  | 
|                                   | 
|                 # Ìí¼Óÿ¸öº¯Êý·µ»ØµÄ±¨¸æ  | 
|                 execCount, funReport = funcObj.GetFuncReport(self.contentList, outputMode)  | 
|                 tempReport += funReport  | 
| #                self.pyExecCount += int(execCount)  | 
|   | 
|         # py±¨¸æ     | 
|         if self.pyTotalCount == 0:  | 
|             LogEx(1, 'PyTotalRowsCount Zero:%s'%self.pyName)  | 
|             pyReport = '¡¾%s¡¿ state:[0/0]  percent:[100%%]%s'%(self.pyName, CRLF*2)  | 
|         else:  | 
|             pyReport = '¡¾%s¡¿ '%self.pyName  | 
|             pyReport += 'state:[%s/%s]  '%(self.pyExecCount, self.pyTotalCount)  | 
|             pyReport += 'percent:[%0.02f%%]  '%(self.GetExecPercent())  | 
|             pyReport += '%s'%(CRLF*2)  | 
|           | 
|         # ¸½¼ÓÐÅÏ¢ºÍMD5ÑéÖ¤Âë  | 
|         if outputMode == FILE_OUTPUT_MODE:  | 
|             if not self.MD5:  | 
|                 self.MD5 = CalcListMD5(self.contentList, self.MD5Key)  | 
|             tempReport += '%sPyÎļþMD5:[%s]'%(CRLF*2, self.MD5)  | 
|             reportMD5 = CalcStringMD5(pyReport + tempReport + CRLF, self.MD5Key)  | 
|             tempReport += '%s²âÊÔ±¨¸æMD5:[%s]%s'%(CRLF*2, reportMD5, CRLF*2)  | 
|             tempReport += '±£´æÊ±¼ä:[%s-%s-%s %s:%s:%s]'%tuple(['%02d'%time.localtime()[i] for i in range(6)])  | 
|           | 
|         return pyReport + tempReport      | 
|       | 
|       | 
|     ## Çå³ýPyÖ´ÐÐÐÅÏ¢  | 
|     #  @param ²ÎÊý  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£ºPy  | 
|     def ClearState(self):  | 
|             | 
|         self.pyExecCount = 0  | 
|         self.isTracking = False  | 
|           | 
|         for funcObj in self.funcObjList:  | 
|             funcObj.ClearState()  | 
|   | 
|   | 
| ## º¯ÊýÀà  | 
| #  | 
| # ¹ÜÀíº¯ÊýÖÐÿÐеÄÖ´ÐÐÇé¿ö  | 
| class FuncObj:  | 
|       | 
|     ## ¹¹Ôì  | 
|     #  @param className: ËùÊôÀàÃû  | 
|     #  @param funcName: º¯ÊýÃû  | 
|     #  @param funcComment: º¯Êý×¢ÊÍ   | 
|     #  @param rowInfoList: ËùÓÐÐÐÐÅÏ¢  | 
|     #  @param startIndex: º¯ÊýÆðʼ  | 
|     #  @param endIndex: º¯Êý½áÊø  | 
|     #  @param MD5: º¯ÊýMD5  | 
|     #  @param returnValue: ·µ»ØÖµ  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
|     def __init__(self, className, funcName, funcComment, rowInfoList, startIndex, endIndex, MD5, returnValue=None):  | 
|         self.className = className         # ËùÊôÀàÃû  | 
|         self.funcName = funcName           # º¯ÊýÃû  | 
|         self.funcComment = funcComment     # º¯Êý×¢ÊÍ     | 
|         self.execRowCount = 0              # ÒÑÖ´ÐÐÐÐÊý   | 
|         self.totalRowCount = 0             # ×ÜÐÐÊý  | 
|         self.rowObjDict = {}               # ÐжÔÏóÁÐ±í  | 
|         self.returnValue = returnValue     # ·µ»ØÖµ  | 
|         self.startIndex = startIndex       # º¯ÊýÆðʼ  | 
|         self.endIndex = endIndex           # º¯Êý½áÊø  | 
|         self.isTracking = False            # ÊÇ·ñÊÇ×·×ÙÖÐ  | 
|         self.MD5 = MD5     # MD5  | 
|           | 
|         self.CreateRowInfo(rowInfoList)    # Éú³ÉÐжÔÏó  | 
|         self.CalcRowExecCount()            # ¼ÆËãÖ´ÐÐÐÐÊý£¬ºÍ×ÜÐÐÊý  | 
|       | 
|       | 
|     ## Éú³ÉÐжÔÏó  | 
|     #  @param rowInfo:ÐÐÐÅÏ¢  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
|     def CreateRowInfo(self, rowInfo):  | 
|           | 
|         for i in rowInfo:  | 
|             #´´½¨ÐжÔÏó  | 
|             tempRowObj = RowObj(i[0], i[1], i[2], i[3])  | 
|             #±£´æÐжÔÏó  | 
|             self.rowObjDict[i[0]] = tempRowObj  | 
|               | 
|               | 
|     ## ¼ÆË㺯Êý¿ÉÖ´ÐÐÐÐÊý£¬ºÍ×ÜÐÐÊý  | 
|     #  @param ²ÎÊý  | 
|     #  @return £¨Ö´ÐÐÐÐÊý£¬×ÜÐÐÊý£©  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º¼ÆË㺯Êý¿ÉÖ´ÐÐÐÐÊý£¬ºÍ×ÜÐÐÊý  | 
|     def CalcRowExecCount(self):  | 
|           | 
|         self.execRowCount = 0  | 
|         self.totalRowCount = 0  | 
|           | 
|         for rowObj in self.rowObjDict.values():  | 
|             if rowObj.GetRowInfo()[2] == 1:  | 
|                 self.execRowCount += 1  | 
|             if rowObj.GetRowInfo()[2] < 2:  | 
|                 self.totalRowCount += 1  | 
|                   | 
|         return (self.execRowCount, self.totalRowCount)  | 
|       | 
|       | 
|     ## ¸üÐÂÐÐ״̬  | 
|     #  @param rowIndex: ÐкŠ | 
|     #  @param returnValue: ·µ»ØÖµ  | 
|     #  @return ·µ»ØÊÇ·ñ¸Ä±ä  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
|     def UpdateRowState(self, rowIndex, returnValue):  | 
|         self.returnValue = returnValue  | 
|   | 
|         if self.rowObjDict.has_key(rowIndex):  | 
|             if self.rowObjDict[rowIndex].ChangeRowState():  | 
|                 self.execRowCount += 1  | 
|                 return True  | 
| #        else:  | 
| #            LogEx(0, 'Func:%s has no row:%s'%(self.funcName,rowIndex))  | 
|           | 
|         return False  | 
|       | 
|   | 
|     ## »ñµÃº¯ÊýÃû  | 
|     #  @param ²ÎÊý  | 
|     #  @return º¯ÊýÃû  | 
|     #  @remarks »ñµÃº¯ÊýÃû  | 
|     def GetName(self):  | 
|           | 
|         return  self.funcName  | 
|                                           | 
|                       | 
|     ## »ñµÃº¯ÊýMD5  | 
|     #  @param ²ÎÊý  | 
|     #  @return º¯ÊýMD5  | 
|     #  @remarks »ñµÃº¯ÊýMD5  | 
|     def GetMD5(self):  | 
|           | 
|         return  self.MD5      | 
|              | 
|                       | 
|     ## »ñµÃº¯ÊýÖ´ÐÐÂÊ  | 
|     #  @param ²ÎÊý  | 
|     #  @return º¯ÊýÖ´ÐÐÂÊ  | 
|     #  @remarks»ñµÃº¯ÊýÖ´ÐÐÂÊ  | 
|     def GetExecPercent(self):  | 
|           | 
|         if self.totalRowCount == 0:  | 
|             return 0.0  | 
|         return  float(self.execRowCount)/self.totalRowCount*100  | 
|               | 
|           | 
|     ## ÉèÖÃ×·×Ù  | 
|     #  @param isTracking: ÊÇ·ñ×·×ÙÖÐ  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£ºÉèÖÃ×·×Ù  | 
|     def SetTrack(self, isTracking):  | 
|           | 
|         self.isTracking = isTracking     | 
|       | 
|       | 
|     ## »ñÈ¡º¯ÊýÐÅÏ¢  | 
|     #  @param ²ÎÊý  | 
|     #  @return º¯ÊýÐÅÏ¢  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º±¾º¯ÊýµÄÐÅÏ¢  | 
|     def GetFuncInfo(self):  | 
|           | 
|         return (self.className,        # ËùÊôÀàÃû  | 
|                 self.funcName,         # º¯ÊýÃû  | 
|                 self.funcComment,      # º¯Êý×¢ÊÍ    | 
|                 self.execRowCount,     # ÒÑÖ´ÐÐÐÐÊý  | 
|                 self.totalRowCount,    # ×ÜÐÐÊý  | 
|                 self.rowObjDict,       # ÐжÔÏó×Öµä  | 
|                 self.returnValue,      # ·µ»ØÖµ  | 
|                 self.startIndex,       # º¯ÊýÆðʼ  | 
|                 self.endIndex,         # º¯Êý½áÊø  | 
|                 self.isTracking,       # ÊÇ·ñÊÇ×·×ÙÖÐ  | 
|                 self.MD5               # º¯ÊýMD5  | 
|                 )  | 
|           | 
|           | 
|     ## ÉèÖú¯ÊýÐÅÏ¢  | 
|     #  @param className: ËùÊôÀàÃû  | 
|     #  @param funcName: º¯ÊýÃû  | 
|     #  @param funcComment: º¯Êý×¢ÊÍ  | 
|     #  @param execRowCount: ÒÑÖ´ÐÐÐÐÊý  | 
|     #  @param totalRowCount: ×ÜÐÐÊý  | 
|     #  @param rowObjList: ÐжÔÏóÁÐ±í  | 
|     #  @param startIndex: º¯ÊýÆðʼ  | 
|     #  @param endIndex: º¯Êý½áÊø  | 
|     #  @param MD5: º¯ÊýMD5  | 
|     #  @param returnValue: ·µ»ØÖµ  | 
|     #  @param isTracking: ÊÇ·ñÊÇ×·×ÙÖÐ  | 
|     #  @return PyÐÅÏ¢  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£ºÉèÖú¯ÊýÐÅÏ¢  | 
|     def SetFuncInfo(self, className, funcName, funcComment, execRowCount, totalRowCount, \  | 
|                     rowObjList, startIndex, endIndex, MD5, returnValue=None, isTracking=False):  | 
|           | 
|         self.className = className            # ËùÊôÀàÃû  | 
|         self.funcName = funcName              # º¯ÊýÃû  | 
|         self.funcComment = funcComment        # º¯Êý×¢ÊÍ     | 
|         self.execRowCount = execRowCount      # ÒÑÖ´ÐÐÐÐÊý   | 
|         self.totalRowCount = totalRowCount    # ×ÜÐÐÊý  | 
|         self.rowObjList = rowObjList          # ÐжÔÏó×Öµä  | 
|         self.returnValue = returnValue        # ·µ»ØÖµ  | 
|         self.startIndex = startIndex          # º¯ÊýÆðʼ  | 
|         self.endIndex = endIndex              # º¯Êý½áÊø  | 
|         self.MD5 = MD5                        # º¯ÊýMD5  | 
|         self.isTracking = isTracking          # ÊÇ·ñÊÇ×·×ÙÖÐ  | 
|       | 
|       | 
|     ## »ñÈ¡º¯ÊýÖ´ÐÐÐÅÏ¢  | 
|     #  @param contentList: PYÄÚÈÝ  | 
|     #  @param showMode: Êä³öģʽ£¬0 ½çÃæ¡¢1 Îļþ  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º·µ»Øº¯ÊýµÄ±»Ö´ÐÐÇé¿ö  | 
|     def GetFuncReport(self, contentList, outputMode):  | 
| #        LogEx(0, "GetFuncReport()")  | 
|         # º¯ÊýÖ´Ðб¨¸æ  | 
|         funcReport = ''  | 
|         CRLF = "\r\n"  | 
|           | 
|         # Èç¹ûÓк¯Êý×¢ÊÍ  | 
|         if self.funcComment:  | 
|             # Ìí¼Ó×¢ÊÍ  | 
|             funcReport += self.funcComment.strip('\r\n')  | 
|         # Ìí¼ÓMD5  | 
|         funcReport += '    MD5:[%s]'%self.MD5 + CRLF  | 
|               | 
| #===============================================================================  | 
| #        self.execRowCount = 0  # Çå¿ÕÒÑÖ´ÐÐÐÐÊý  | 
| #        keys = self.rowObjDict.keys()  | 
| #        keys.sort()  | 
| #        for key in keys:  | 
| #            state = self.rowObjDict[key].GetRowInfo()[2]  | 
| #            #ÒÑÖ´ÐÐÐÐ  | 
| #            if state == 1:  | 
| #                self.execRowCount += 1  | 
| #===============================================================================  | 
|           | 
|         # ---ÒÑÖ´ÐÐÐÐÊý/×ÜÐÐÊý¡¢Ö´ÐÐÂÊ¡¢ÆðÖ¹ÐÐÊý¡¢·µ»ØÖµ¡¢·µ»ØÖµÀàÐÍ---  | 
|         if self.totalRowCount == 0:  | 
|             LogEx(1, 'FuncRows Zero:%s'%self.funcName)  | 
|               | 
|             if self.className:  | 
|                 funcReport += '    [%s]:'%self.className  | 
|                 funcReport += ':<%s>  state:[0/0]  percent:[100%%]  '%(self.funcName)  | 
|             else:  | 
|                 funcReport += '    [Func]:'  | 
|                 funcReport += ' <%s>  state:[0/0]  percent:[100%%]  '%(self.funcName)  | 
|                   | 
|                   | 
|             funcReport += 'range:[%d:%d]  '%(self.startIndex, self.endIndex)  | 
|             funcReport += 'returnValue:[%s]  '%(self.returnValue)  | 
|             funcReport += 'type:[%s]%s'%(type(self.returnValue), CRLF)  | 
|               | 
|             return 0, funcReport  | 
|           | 
|         if self.className:  | 
|             funcReport += '    [%s]:'%self.className + ':<%s>  '%self.funcName  | 
|         else:  | 
|             funcReport += '    [Func]:' + ' <%s>  '%(self.funcName)  | 
|           | 
|         funcReport += 'state:[%s/%s]  '%(self.execRowCount, self.totalRowCount)  | 
|         funcReport += 'percent:[%0.02f%%]  '%(float(self.execRowCount)/self.totalRowCount*100)  | 
|         funcReport += 'range:[%d:%d]  '%(self.startIndex, self.endIndex)  | 
|         funcReport += 'returnValue:[%s]  '%(self.returnValue)  | 
|         funcReport += 'type:[%s]%s'%(type(self.returnValue), CRLF)  | 
|   | 
|         # ¼ÆËãÐкÅλÊý  | 
|         count = 1  | 
|         num = len(contentList)/10  | 
|         while num > 0:  | 
|             num = num/10  | 
|             count += 1  | 
|           | 
|         formatString = "[%0" + str(count) + "d] %s"  | 
|           | 
|         for i in range(self.startIndex, self.endIndex):  | 
|             # ´úÂë  | 
|             if self.rowObjDict.has_key(i+1):  | 
|                 state = self.rowObjDict[i + 1].GetRowInfo()[2]  | 
|                 sentance = self.rowObjDict[i + 1].GetRowInfo()[3]  | 
|                 # Ö´Ðйý  | 
|                 if state == 1:  | 
|                     funcReport += '        ' + (formatString)%(i + 1, sentance.strip('\r\n')) + CRLF  | 
|   | 
|                 # Î´Ö´Ðйý£¬¼Ó*  | 
|                 elif state == 0:  | 
|                     funcReport += '*      '  | 
|                     # Êä³öµ½Îļþ£¬¶à¼ÓÒ»¸ö¿Õ¸ñ  | 
|                     if outputMode == FILE_OUTPUT_MODE:  | 
|                         funcReport += ' '  | 
|                     funcReport += (formatString)%(i + 1, sentance.strip('\r\n')) + CRLF  | 
|                 # ×¢Êͼ°ºöÂÔÏî  | 
|                 elif len(sentance.strip()) > 0:  | 
|                     funcReport += '        ' + (formatString)%(i + 1, sentance.strip('\r\n')) + CRLF  | 
|                       | 
| #===============================================================================  | 
| #            elif len(contentList[i].strip()) > 0:  | 
| #                funcReport += '        ' + (formatString)%(i+1, contentList[i].strip('\r\n')) + CRLF  | 
| #===============================================================================  | 
|              | 
|         funcReport += CRLF  | 
|             | 
|         return self.execRowCount,funcReport  | 
|       | 
|       | 
|     ## Çå³ýº¯ÊýÖ´ÐÐÐÅÏ¢  | 
|     #  @param ²ÎÊý  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£ºÇå³ý±¾º¯ÊýÖ´ÐÐÇé¿ö  | 
|     def ClearState(self):  | 
|             | 
|         self.execRowCount = 0  | 
|         self.returnValue = None  | 
|         self.isTracking = False   | 
|           | 
|         for rowObj in self.rowObjDict.values():  | 
|             rowObj.ClearState()  | 
|   | 
|   | 
| ## ÐÐÄÚÈÝÀà  | 
| #  | 
| # ¹ÜÀí±¾Ðеı»Ö´ÐÐÇé¿ö  | 
| class RowObj:  | 
|       | 
|     ## ¹¹Ô캯Êý  | 
|     #  @param rowIndex: ÐкŠ | 
|     #  @param rowOffset: ÐкÅÏà¶ÔÓ뺯Êý¶¨ÒåλÖÃµÄÆ«ÒÆ  | 
|     #  @param rowState: ÐÐÖ´ÐÐ״̬  | 
|     #  @param content: ÐÐÄÚÈÝ  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
|     def __init__(self, rowIndex, rowOffset, rowState, content):  | 
|         self.index = rowIndex            # ÐкŠ | 
|         self.offset = rowOffset          # ÐкÅÏà¶ÔÓ뺯Êý¶¨ÒåλÖÃµÄÆ«ÒÆ  | 
|         self.state = rowState            # Ö´ÐÐ״̬  | 
|         self.content = content           # ÐÐÄÚÈÝ  | 
|       | 
|       | 
|     ## ¸üÐÂÐÐ״̬  | 
|     #  @param ²ÎÊý  | 
|     #  @return ÊÇ·ñ¸Ä±ä  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
|     def ChangeRowState(self):  | 
|         if self.state == 0:  | 
|             self.state = 1  | 
|             return True  | 
|           | 
|         return False  | 
|       | 
|       | 
|     ## »ñÈ¡ÐÐÖ´ÐÐÐÅÏ¢  | 
|     #  @param ²ÎÊý  | 
|     #  @return (rowIndex:ÐкÅ,rowOffset:ÐкÅÏà¶ÔÓ뺯Êý¶¨ÒåλÖÃµÄÆ«ÒÆ,rowState:ÐÐÖ´ÐÐ״̬,self.content:ÐÐÄÚÈÝ)  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£º±¾ÐÐÄÚÈݵÄÖ´ÐÐÇé¿ö  | 
|     def GetRowInfo(self):  | 
|         return (self.index, self.offset, self.state, self.content)  | 
|       | 
|       | 
|     ## Çå³ýÐÐÖ´ÐÐÐÅÏ¢  | 
|     #  @param ²ÎÊý  | 
|     #  @return ·µ»ØÖµ  | 
|     #  @remarks º¯ÊýÏêϸ˵Ã÷£ºÇå³ý±¾ÐÐÖ´ÐÐÇé¿ö  | 
|     def ClearState(self):  | 
|         self.state = 0  | 
|   | 
|   | 
| #-------------------------------------------------------------------------------  | 
|   | 
| ## »ñµÃPyObjʵÀý  | 
| #  @param pyName: ÎļþÃû  | 
| #  @param MD5Key£ºMD5ÃÜÔ¿  | 
| #  @param scriptPath: Py·¾¶  | 
| #  @param isCreate: ÊÇ·ñ¸ù¾ÝPYÉú³ÉPyObj  | 
| #  @return ·µ»ØPyObj  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
| def GetPyObj(pyName, MD5Key, scriptPath="", isCreate=True):  | 
|       | 
|     return PyObj(pyName, MD5Key, scriptPath, isCreate)  | 
|   | 
|   | 
| ## »ñµÃFuncObjʵÀý  | 
| #  @param className: ËùÊôÀàÃû  | 
| #  @param funcName: º¯ÊýÃû  | 
| #  @param funcComment: º¯Êý×¢ÊÍ   | 
| #  @param rowInfoList: ËùÓÐÐÐÐÅÏ¢  | 
| #  @param startIndex: º¯ÊýÆðʼ  | 
| #  @param endIndex: º¯Êý½áÊø  | 
| #  @param MD5: º¯ÊýMD5  | 
| #  @param totalRowCount: ·µ»ØÖµ  | 
| #  @return ·µ»ØFuncObj  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷£º  | 
| def GetFuncObj(className, funcName, funcComment, rowInfoList, startIndex, endIndex, MD5, returnValue=None):  | 
|       | 
|     return FuncObj(className, funcName, funcComment, rowInfoList, startIndex, endIndex, MD5, returnValue)  | 
|   |