def _handleNestedCode(func_code, code, codeSource): """ @param func_code: the code object for the nested code @type func_code: L{types.CodeType} @param code: the parent code in which the code is nested @type code: L{CodeChecks.Code} @type codeSource: L{Codechecks.CodeSource} """ nested = not (codeSource.main or codeSource.in_class) if func_code.co_name == utils.LAMBDA or nested: utils.debug(' handling nested code %s under %r for %r', func_code.co_name, codeSource.func, code.func) varnames = None if nested and func_code.co_name != utils.LAMBDA: varnames = func_code.co_varnames + \ codeSource.calling_code[-1].function.func_code.co_varnames # save the original func return value and restore after checking func = code.func returnValues = code.returnValues # we don't want suppressions from nested code to bleed into the # containing code block, or the next nested code on the same level utils.pushConfig() code.init( function.create_fake(func_code.co_name, func_code, {}, varnames)) _checkCode(code, codeSource) utils.popConfig() # restore code.init(func) code.returnValues = returnValues
def getSuppression(name, suppressions, warnings) : try : utils.pushConfig() # cheesy hack to deal with new-style classes. i don't see a # better way to get the name, '<' is an invalid identifier, so # we can reliably check it and extract name from: # <class 'class-name'>[.identifier[.identifier]...] matches = _CLASS_NAME_RE.match(name) if matches: # pull out the names and make a complete identifier (ignore None) name = string.join(filter(None, matches.groups()), '') suppress = suppressions[0].get(name, None) if suppress is not None : _updateSuppressions(suppress, warnings) regexList = suppressions[1].keys() regexList.sort() for regex in regexList : match = regex.match(name) if match and match.group() == name : suppress = 1 _updateSuppressions(suppressions[1][regex], warnings) if not suppress : utils.popConfig() return suppress except _SuppressionError : return None
def _initModule(self, module): self.module = module self.attributes = dir(self.module) pychecker_attr = getattr(module, Config.CHECKER_VAR, None) if pychecker_attr is not None : utils.pushConfig() utils.updateCheckerArgs(pychecker_attr, 'suppressions', 0, []) for tokenName in _filterDir(self.module, _DEFAULT_MODULE_TOKENS) : token = getattr(self.module, tokenName) if isinstance(token, types.ModuleType) : # get the real module name, tokenName could be an alias self.addModule(token.__name__) elif isinstance(token, types.FunctionType) : self.addFunction(token) elif isinstance(token, types.ClassType) or \ hasattr(token, '__bases__') : self.addClass(tokenName) else : self.addVariable(tokenName, type(token)) if pychecker_attr is not None : utils.popConfig() return 1
def _initModule(self, module): self.module = module self.attributes = dir(self.module) pychecker_attr = getattr(module, Config.CHECKER_VAR, None) if pychecker_attr is not None : utils.pushConfig() utils.updateCheckerArgs(pychecker_attr, 'suppressions', 0, []) for tokenName in _filterDir(self.module, _DEFAULT_MODULE_TOKENS) : if _EVIL_C_OBJECTS.has_key('%s.%s' % (self.moduleName, tokenName)): continue # README if interpreter is crashing: # Change 0 to 1 if the interpretter is crashing and re-run. # Follow the instructions from the last line printed. if 0: print "Add the following line to _EVIL_C_OBJECTS:\n" \ " '%s.%s': None, " % (self.moduleName, tokenName) token = getattr(self.module, tokenName) if isinstance(token, types.ModuleType) : # get the real module name, tokenName could be an alias self.addModule(token.__name__) elif isinstance(token, types.FunctionType) : self.addFunction(token) elif isinstance(token, types.ClassType) or \ hasattr(token, '__bases__') : self.addClass(tokenName) else : self.addVariable(tokenName, type(token)) if pychecker_attr is not None : utils.popConfig() return 1
def _initModule(self, module): self.module = module self.attributes = dir(self.module) pychecker_attr = getattr(module, Config.CHECKER_VAR, None) if pychecker_attr is not None: utils.pushConfig() utils.updateCheckerArgs(pychecker_attr, 'suppressions', 0, []) for tokenName in _filterDir(self.module, _DEFAULT_MODULE_TOKENS): token = getattr(self.module, tokenName) if isinstance(token, types.ModuleType): # get the real module name, tokenName could be an alias self.addModule(token.__name__) elif isinstance(token, types.FunctionType): self.addFunction(token) elif isinstance(token, types.ClassType) or \ hasattr(token, '__bases__') : self.addClass(tokenName) else: self.addVariable(tokenName, type(token)) if pychecker_attr is not None: utils.popConfig() return 1
def _handleNestedCode(func_code, code, codeSource): """ @param func_code: the code object for the nested code @type func_code: L{types.CodeType} @param code: the parent code in which the code is nested @type code: L{CodeChecks.Code} @type codeSource: L{Codechecks.CodeSource} """ nested = not (codeSource.main or codeSource.in_class) if func_code.co_name == utils.LAMBDA or nested: utils.debug(' handling nested code %s under %r for %r', func_code.co_name, codeSource.func, code.func) varnames = None if nested and func_code.co_name != utils.LAMBDA: varnames = func_code.co_varnames + \ codeSource.calling_code[-1].function.func_code.co_varnames # save the original func return value and restore after checking func = code.func returnValues = code.returnValues # we don't want suppressions from nested code to bleed into the # containing code block, or the next nested code on the same level utils.pushConfig() code.init(function.create_fake(func_code.co_name, func_code, {}, varnames)) _checkCode(code, codeSource) utils.popConfig() # restore code.init(func) code.returnValues = returnValues
def _initModule(self, module): self.module = module self.attributes = dir(self.module) pychecker_attr = getattr(module, Config.CHECKER_VAR, None) if pychecker_attr is not None: utils.pushConfig() utils.updateCheckerArgs(pychecker_attr, 'suppressions', 0, []) for tokenName in _filterDir(self.module, _DEFAULT_MODULE_TOKENS): if _EVIL_C_OBJECTS.has_key('%s.%s' % (self.moduleName, tokenName)): continue # README if interpreter is crashing: # Change 0 to 1 if the interpretter is crashing and re-run. # Follow the instructions from the last line printed. if 0: print "Add the following line to _EVIL_C_OBJECTS:\n" \ " '%s.%s': None, " % (self.moduleName, tokenName) token = getattr(self.module, tokenName) if isinstance(token, types.ModuleType): # get the real module name, tokenName could be an alias self.addModule(token.__name__) elif isinstance(token, types.FunctionType): self.addFunction(token) elif isinstance(token, types.ClassType) or \ hasattr(token, '__bases__') : self.addClass(tokenName) else: self.addVariable(tokenName, type(token)) if pychecker_attr is not None: utils.popConfig() return 1
def getSuppression(name, suppressions, warnings): try: utils.pushConfig() # cheesy hack to deal with new-style classes. i don't see a # better way to get the name, '<' is an invalid identifier, so # we can reliably check it and extract name from: # <class 'class-name'>[.identifier[.identifier]...] matches = _CLASS_NAME_RE.match(name) if matches: # pull out the names and make a complete identifier (ignore None) name = string.join(filter(None, matches.groups()), '') suppress = suppressions[0].get(name, None) if suppress is not None: _updateSuppressions(suppress, warnings) regexList = suppressions[1].keys() regexList.sort() for regex in regexList: match = regex.match(name) if match and match.group() == name: suppress = 1 _updateSuppressions(suppressions[1][regex], warnings) if not suppress: utils.popConfig() return suppress except _SuppressionError: return None
def _handleNestedCode(func_code, code, codeSource): nested = not (codeSource.main or codeSource.in_class) if func_code.co_name == utils.LAMBDA or nested: utils.debug(' handling nested code %s under %r', func_code.co_name, codeSource.func) varnames = None if nested and func_code.co_name != utils.LAMBDA: varnames = func_code.co_varnames + \ codeSource.calling_code[-1].function.func_code.co_varnames # save the original return value and restore after checking returnValues = code.returnValues # we don't want suppressions from nested code to bleed into the # containing code block, or the next nested code on the same level utils.pushConfig() code.init(function.create_fake(func_code.co_name, func_code, {}, varnames)) _checkCode(code, codeSource) utils.popConfig() code.returnValues = returnValues
def _initModule(self, module): self.module = module self.attributes = dir(self.module) # interpret module-specific suppressions pychecker_attr = getattr(module, Config.CHECKER_VAR, None) if pychecker_attr is not None : utils.pushConfig() utils.updateCheckerArgs(pychecker_attr, 'suppressions', 0, []) # read all tokens from the real module, and register them for tokenName in _getModuleTokens(self.module): if EVIL_C_OBJECTS.has_key('%s.%s' % (self.moduleName, tokenName)): continue # README if interpreter is crashing: # Change 0 to 1 if the interpretter is crashing and re-run. # Follow the instructions from the last line printed. if utils.cfg().findEvil: print "Add the following line to EVIL_C_OBJECTS or the string to evil in a config file:\n" \ " '%s.%s': None, " % (self.moduleName, tokenName) token = getattr(self.module, tokenName) if isinstance(token, types.ModuleType) : # get the real module name, tokenName could be an alias self.addModule(token.__name__) elif isinstance(token, types.FunctionType) : self.addFunction(token) elif isinstance(token, types.ClassType) or \ hasattr(token, '__bases__') and \ issubclass(type(token), type): self.addClass(tokenName) else : self.addVariable(tokenName, type(token)) if pychecker_attr is not None : utils.popConfig() return 1
def _initModule(self, module): self.module = module self.attributes = dir(self.module) # interpret module-specific suppressions pychecker_attr = getattr(module, Config.CHECKER_VAR, None) if pychecker_attr is not None: utils.pushConfig() utils.updateCheckerArgs(pychecker_attr, 'suppressions', 0, []) # read all tokens from the real module, and register them for tokenName in _getModuleTokens(self.module): if EVIL_C_OBJECTS.has_key('%s.%s' % (self.moduleName, tokenName)): continue # README if interpreter is crashing: # Change 0 to 1 if the interpretter is crashing and re-run. # Follow the instructions from the last line printed. if utils.cfg().findEvil: print "Add the following line to EVIL_C_OBJECTS or the string to evil in a config file:\n" \ " '%s.%s': None, " % (self.moduleName, tokenName) token = getattr(self.module, tokenName) if isinstance(token, types.ModuleType): # get the real module name, tokenName could be an alias self.addModule(token.__name__) elif isinstance(token, types.FunctionType): self.addFunction(token) elif isinstance(token, types.ClassType) or \ hasattr(token, '__bases__') and \ issubclass(type(token), type): self.addClass(tokenName) else: self.addVariable(tokenName, type(token)) if pychecker_attr is not None: utils.popConfig() return 1
def _checkFunction(module, func, c = None, main = 0, in_class = 0) : "Return a list of Warnings found in a function/method." # always push a new config object, so we can pop at end of function utils.pushConfig() code = CodeChecks.Code() code.init(func) if main: for key in func.function.func_globals.keys(): code.unusedLocals[key] = -1 codeSource = CodeChecks.CodeSource(module, func, c, main, in_class, code) try : _checkCode(code, codeSource) if not in_class : _findUnreachableCode(code) # handle lambdas and nested functions codeSource.calling_code.append(func) for func_code in code.codeObjects.values() : _handleNestedCode(func_code, code, codeSource) del codeSource.calling_code[-1] except (SystemExit, KeyboardInterrupt) : exc_type, exc_value, exc_tb = sys.exc_info() raise exc_type, exc_value except : exc_type, exc_value, exc_tb = sys.exc_info() exc_list = traceback.format_exception(exc_type, exc_value, exc_tb) for index in range(0, len(exc_list)) : exc_list[index] = string.replace(exc_list[index], "\n", "\n\t") code.addWarning(msgs.CHECKER_BROKEN % string.join(exc_list, "")) if cfg().checkReturnValues : _checkReturnWarnings(code) if cfg().localVariablesUsed : for var, line in code.unusedLocals.items() : if line is not None and line > 0 and _name_unused(var) : code.addWarning(msgs.UNUSED_LOCAL % var, line) if cfg().argumentsUsed : op = code.getFirstOp() if not (OP.RAISE_VARARGS(op) or OP.RETURN_VALUE(op)) : for var, line in code.unusedLocals.items() : _checkUnusedParam(var, line, func, code) # Check code complexity: # loops should be counted as one branch, but there are typically 3 # branches in byte code to setup a loop, so subtract off 2/3's of them # / 2 to approximate real branches branches = (len(code.branches.keys()) - (2 * code.loops)) / 2 lines = (code.getLineNum() - code.func_code.co_firstlineno) returns = len(code.returnValues) if not main and not in_class : args = code.func_code.co_argcount locals = len(code.func_code.co_varnames) - args _checkComplex(code, cfg().maxArgs, args, func, msgs.TOO_MANY_ARGS) _checkComplex(code, cfg().maxLocals, locals, func, msgs.TOO_MANY_LOCALS) _checkComplex(code, cfg().maxLines, lines, func, msgs.FUNC_TOO_LONG) _checkComplex(code, cfg().maxReturns, returns, func, msgs.TOO_MANY_RETURNS) _checkComplex(code, cfg().maxBranches, branches, func, msgs.TOO_MANY_BRANCHES) if not (main or in_class) : utils.popConfig() func.returnValues = code.returnValues return (code.warnings, code.globalRefs, code.functionsCalled, code.codeObjects.values(), code.returnValues)
def _checkFunction(module, func, c = None, main = 0, in_class = 0) : """ Return a list of Warnings found in a function/method. @type module: L{pychecker.checker.PyCheckerModule} """ # always push a new config object, so we can pop at end of function utils.pushConfig() code = CodeChecks.Code() code.init(func) if main: for key in func.function.func_globals.keys(): code.unusedLocals[key] = -1 codeSource = CodeChecks.CodeSource(module, func, c, main, in_class, code) try : _checkCode(code, codeSource) if not in_class : _findUnreachableCode(code) # handle lambdas and nested functions codeSource.calling_code.append(func) for key in code.codeOrder: func_code = code.codeObjects[key] _handleNestedCode(func_code, code, codeSource) del codeSource.calling_code[-1] except (SystemExit, KeyboardInterrupt) : exc_type, exc_value, exc_tb = sys.exc_info() raise exc_type, exc_value except : exc_type, exc_value, exc_tb = sys.exc_info() exc_list = traceback.format_exception(exc_type, exc_value, exc_tb) for index in range(0, len(exc_list)) : exc_list[index] = string.replace(exc_list[index], "\n", "\n\t") code.addWarning(msgs.CHECKER_BROKEN % string.join(exc_list, "")) if cfg().checkReturnValues : _checkReturnWarnings(code) if cfg().localVariablesUsed : for var, line in code.unusedLocals.items() : if line is not None and line > 0 and _name_unused(var) : code.addWarning(msgs.UNUSED_LOCAL % var, line) if cfg().argumentsUsed : op = code.getFirstOp() if not (OP.RAISE_VARARGS(op) or OP.RETURN_VALUE(op)) : for var, line in code.unusedLocals.items() : _checkUnusedParam(var, line, func, code) # Check code complexity: # loops should be counted as one branch, but there are typically 3 # branches in byte code to setup a loop, so subtract off 2/3's of them # / 2 to approximate real branches branches = (len(code.branches.keys()) - (2 * code.loops)) / 2 lines = (code.getLineNum() - code.func_code.co_firstlineno) returns = len(code.returnValues) if not main and not in_class : args = code.func_code.co_argcount localCount = len(code.func_code.co_varnames) - args _checkComplex(code, cfg().maxArgs, args, func, msgs.TOO_MANY_ARGS) _checkComplex(code, cfg().maxLocals, localCount, func, msgs.TOO_MANY_LOCALS) _checkComplex(code, cfg().maxLines, lines, func, msgs.FUNC_TOO_LONG) _checkComplex(code, cfg().maxReturns, returns, func, msgs.TOO_MANY_RETURNS) _checkComplex(code, cfg().maxBranches, branches, func, msgs.TOO_MANY_BRANCHES) if not (main or in_class) : utils.popConfig() func.returnValues = code.returnValues # FIXME: I don't think code.codeObjects.values() ever gets used, # but if it does, and needs to be in order, then use code.codeOrder here. return (code.warnings, code.globalRefs, code.functionsCalled, code.codeObjects.values(), code.returnValues)
def _checkFunction(module, func, classObject=None, main=0, in_class=0): """ Return a list of Warnings found in a function/method. @type module: L{pychecker.checker.PyCheckerModule} @type func: L{function.Function} @param classObject: the class object, if applicable @type classObject: L{pychecker.checker.Class} or None @param main: whether this code block is in the source's global namespace (__main__) @type main: int (used as bool) @param in_class: whether this code block is inside a class scope @type in_class: int (used as bool) """ # always push a new config object, so we can pop at end of function utils.pushConfig() code = CodeChecks.Code() code.init(func) if main: for key in func.function.func_globals.keys(): code.unusedLocals[key] = -1 codeSource = CodeChecks.CodeSource( module, func, classObject, main, in_class, code) module.codes.append(code) try : _checkCode(code, codeSource) if not in_class : _findUnreachableCode(code) # handle lambdas and nested functions codeSource.calling_code.append(func) for key in code.codeOrder: func_code = code.codeObjects[key] _handleNestedCode(func_code, code, codeSource) del codeSource.calling_code[-1] assert code.func == codeSource.func except (SystemExit, KeyboardInterrupt) : exc_type, exc_value, exc_tb = sys.exc_info() raise exc_type, exc_value except : exc_type, exc_value, exc_tb = sys.exc_info() exc_list = traceback.format_exception(exc_type, exc_value, exc_tb) for index in range(0, len(exc_list)) : exc_list[index] = string.replace(exc_list[index], "\n", "\n\t") code.addWarning(msgs.CHECKER_BROKEN % string.join(exc_list, "")) if cfg().checkReturnValues : _checkReturnWarnings(code) if cfg().localVariablesUsed : for var, line in code.unusedLocals.items() : if line is not None and line > 0 and _name_unused(var) : code.addWarning(msgs.UNUSED_LOCAL % var, line) if cfg().argumentsUsed : op = code.getFirstOp() if not (OP.RAISE_VARARGS(op) or OP.RETURN_VALUE(op)) : for var, line in code.unusedLocals.items() : _checkUnusedParam(var, line, func, code) # Check code complexity: # loops should be counted as one branch, but there are typically 3 # branches in byte code to setup a loop, so subtract off 2/3's of them # / 2 to approximate real branches branches = (len(code.branches.keys()) - (2 * code.loops)) / 2 lines = (code.getLineNum() - code.func_code.co_firstlineno) returns = len(code.returnValues) if not main and not in_class : args = code.func_code.co_argcount localCount = len(code.func_code.co_varnames) - args _checkComplex(code, cfg().maxArgs, args, func, msgs.TOO_MANY_ARGS) _checkComplex(code, cfg().maxLocals, localCount, func, msgs.TOO_MANY_LOCALS) _checkComplex(code, cfg().maxLines, lines, func, msgs.FUNC_TOO_LONG) _checkComplex(code, cfg().maxReturns, returns, func, msgs.TOO_MANY_RETURNS) _checkComplex(code, cfg().maxBranches, branches, func, msgs.TOO_MANY_BRANCHES) if not (main or in_class) : utils.popConfig() func.returnValues = code.returnValues # FIXME: I don't think code.codeObjects.values() ever gets used, # but if it does, and needs to be in order, then use code.codeOrder here. # FIXME: should this not be returning copies of globalRefs ? return (code.warnings, code.globalRefs, code.functionsCalled, code.codeObjects.values(), code.returnValues)