Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
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
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
    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
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
0
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)
Ejemplo n.º 14
0
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)