Example #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
Example #2
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
Example #3
0
 def _setupMainCode(self, handle, filename, module):
     try:
         self.mainCode = function.create_from_file(handle, filename, module)
         if handle != None:
             handle.close()
     except TypeError:
         # compile() expected string without null bytes
         utils.debug("Could not load function from file %s, module %r" %
                     (filename, module))
         if handle != None:
             handle.close()
         raise
Example #4
0
 def _setupMainCode(self, handle, filename, module):
     try:
         self.mainCode = function.create_from_file(handle, filename, module)
         if handle != None:
             handle.close()
     except TypeError:
         # compile() expected string without null bytes
         utils.debug("Could not load function from file %s, module %r" % (
             filename, module))
         if handle != None:
             handle.close()
         raise
Example #5
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')
        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
        code.init(
            function.create_fake(func_code.co_name, func_code, {}, varnames))
        _checkCode(code, codeSource)
        code.returnValues = returnValues
Example #6
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')
        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
        code.init(function.create_fake(func_code.co_name, func_code, {},
                                       varnames))
        _checkCode(code, codeSource)
        code.returnValues = returnValues
Example #7
0
    def loadFile(self, filename):
        """
        Load suppressions from the given file.

        @type  filename: str

        @rtype: tuple of (dict, dict)
        """
        suppressions = {}
        suppressionRegexs = {}

        try:
            tmpGlobals, tmpLocals = {}, {}
            execfile(filename, tmpGlobals, tmpLocals)

            suppressions = _getSuppressions('suppressions', tmpLocals,
                                            filename)
            regexs = _getSuppressions('suppressionRegexs', tmpLocals, filename)

            # debug them here, since the options in tmpLocals can turn off
            # debugging again

            # We don't have an active config here yet.  Push ourselves,
            # since we first got loaded with command line arguments,
            # and so -d shows these suppression messages
            from pychecker import utils
            utils.initConfig(self)
            if suppressions:
                utils.debug('Loaded %d suppressions from %s',
                            len(suppressions), filename)
            if suppressionRegexs:
                utils.debug('Loaded %d suppression regexs from %s',
                            len(suppressionRegexs), filename)
            utils.popConfig()

            # now set our attributes based on the locals
            for key, value in tmpLocals.items():
                if self.__dict__.has_key(key):
                    self.__dict__[key] = value
                elif key not in ('suppressions', 'suppressionRegexs') and \
                     key[0] != '_':
                    print "Warning, option (%s) doesn't exist, ignoring" % key

            for regex_str in regexs.keys():
                regex = re.compile(regex_str)
                suppressionRegexs[regex] = regexs[regex_str]
        except IOError:
            pass  # ignore if no file
        except Exception, detail:
            print "Warning, error loading defaults file:", filename, detail
Example #8
0
def processFiles(files, cfg=None, pre_process_cb=None):
    """
    @type  files:          list of str
    @type  cfg:            L{Config.Config}
    @param pre_process_cb: callable notifying of module name, filename
    @type  pre_process_cb: callable taking (str, str)
    """

    warnings = []

    # insert this here, so we find files in the local dir before std library
    if sys.path[0] != '':
        sys.path.insert(0, '')

    # ensure we have a config object, it's necessary
    global _cfg
    if cfg is not None:
        _cfg = cfg
    elif _cfg is None:
        _cfg = Config.Config()

    if _cfg.ignoreImportErrors:
        install_ignore__import__()

    utils.initConfig(_cfg)

    utils.debug('Processing %d files' % len(files))

    for file, (moduleName, moduleDir) in zip(files, getModules(files)):
        if callable(pre_process_cb):
            pre_process_cb("module %s (%s)" % (moduleName, file))

        # create and load the PyCheckerModule, tricking sys.path temporarily
        oldsyspath = sys.path[:]
        if moduleDir is not None:
            sys.path.insert(0, moduleDir)
        pcmodule = pcmodules.PyCheckerModule(moduleName, moduleDir=moduleDir)
        loaded = pcmodule.load()
        sys.path = oldsyspath

        if not loaded:
            w = Warning(pcmodule.filename(), 1,
                        msgs.Internal("NOT PROCESSED UNABLE TO IMPORT"))
            warnings.append(w)

    utils.debug('Processed %d files' % len(files))

    utils.popConfig()

    return warnings
Example #9
0
def processFiles(files, cfg=None, pre_process_cb=None):
    """
    @type  files:          list of str
    @type  cfg:            L{Config.Config}
    @param pre_process_cb: callable notifying of module name, filename
    @type  pre_process_cb: callable taking (str, str)
    """
    
    warnings = []

    # insert this here, so we find files in the local dir before std library
    if sys.path[0] != '' :
        sys.path.insert(0, '')

    # ensure we have a config object, it's necessary
    global _cfg
    if cfg is not None:
        _cfg = cfg
    elif _cfg is None:
        _cfg = Config.Config()

    if _cfg.ignoreImportErrors:
        install_ignore__import__()

    utils.initConfig(_cfg)

    utils.debug('Processing %d files' % len(files))

    for file, (moduleName, moduleDir) in zip(files, getModules(files)):
        if callable(pre_process_cb):
            pre_process_cb("module %s (%s)" % (moduleName, file))

        # create and load the PyCheckerModule, tricking sys.path temporarily
        oldsyspath = sys.path[:]
        if moduleDir is not None:
            sys.path.insert(0, moduleDir)
        pcmodule = pcmodules.PyCheckerModule(moduleName, moduleDir=moduleDir)
        loaded = pcmodule.load()
        sys.path = oldsyspath

        if not loaded:
            w = Warning(pcmodule.filename(), 1,
                        msgs.Internal("NOT PROCESSED UNABLE TO IMPORT"))
            warnings.append(w)

    utils.debug('Processed %d files' % len(files))

    utils.popConfig()

    return warnings
Example #10
0
def _findFunctionWarnings(module, globalRefs, warnings, suppressions) :
    for func in module.functions.values() :
        func_code = func.function.func_code
        utils.debug("function:", func_code)

        name = '%s.%s' % (module.moduleName, func.function.__name__)
        suppress = getSuppression(name, suppressions, warnings)
        if cfg().noDocFunc and func.function.__doc__ == None :
            err = msgs.NO_FUNC_DOC % func.function.__name__
            warnings.append(Warning(module.filename(), func_code, err))

        _checkNoSelfArg(func, warnings)
        _updateFunctionWarnings(module, func, None, warnings, globalRefs)
        if suppress is not None :
            utils.popConfig()
Example #11
0
def _findFunctionWarnings(module, globalRefs, warnings, suppressions):
    for func in module.functions.values():
        func_code = func.function.func_code
        utils.debug("function:", func_code)

        name = '%s.%s' % (module.moduleName, func.function.__name__)
        suppress = getSuppression(name, suppressions, warnings)
        if cfg().noDocFunc and func.function.__doc__ == None:
            err = msgs.NO_FUNC_DOC % func.function.__name__
            warnings.append(Warning(module.filename(), func_code, err))

        _checkNoSelfArg(func, warnings)
        _updateFunctionWarnings(module, func, None, warnings, globalRefs)
        if suppress is not None:
            utils.popConfig()
Example #12
0
    def loadFile(self, filename):
        """
        Load suppressions from the given file.

        @type  filename: str

        @rtype: tuple of (dict, dict)
        """
        suppressions = {}
        suppressionRegexs = {}

        try:
            tmpGlobals, tmpLocals = {}, {}
            execfile(filename, tmpGlobals, tmpLocals)

            suppressions = _getSuppressions("suppressions", tmpLocals, filename)
            regexs = _getSuppressions("suppressionRegexs", tmpLocals, filename)

            # debug them here, since the options in tmpLocals can turn off
            # debugging again

            # We don't have an active config here yet.  Push ourselves,
            # since we first got loaded with command line arguments,
            # and so -d shows these suppression messages
            from pychecker import utils

            utils.initConfig(self)
            if suppressions:
                utils.debug("Loaded %d suppressions from %s", len(suppressions), filename)
            if suppressionRegexs:
                utils.debug("Loaded %d suppression regexs from %s", len(suppressionRegexs), filename)
            utils.popConfig()

            # now set our attributes based on the locals
            for key, value in tmpLocals.items():
                if self.__dict__.has_key(key):
                    self.__dict__[key] = value
                elif key not in ("suppressions", "suppressionRegexs") and key[0] != "_":
                    print "Warning, option (%s) doesn't exist, ignoring" % key

            for regex_str in regexs.keys():
                regex = re.compile(regex_str)
                suppressionRegexs[regex] = regexs[regex_str]
        except IOError:
            pass  # ignore if no file
        except Exception, detail:
            print "Warning, error loading defaults file:", filename, detail
Example #13
0
def _findFunctionWarnings(module, globalRefs, warnings, suppressions) :
    """
    @type  module: L{pychecker.checker.PyCheckerModule}
    """
    for func in module.functions.values() :
        func_code = func.function.func_code
        utils.debug("function:", func_code)

        name = '%s.%s' % (module.moduleName, func.function.__name__)
        suppress = getSuppression(name, suppressions, warnings)
        if cfg().noDocFunc and func.function.__doc__ == None :
            err = msgs.NO_FUNC_DOC % func.function.__name__
            # FIXME: is there a good reason why this passes func_code as line ?
            warnings.append(Warning(module.filename(), func_code, err))

        _checkNoSelfArg(func, warnings)
        _updateFunctionWarnings(module, func, None, warnings, globalRefs)
        if suppress is not None :
            utils.popConfig()
Example #14
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
Example #15
0
def _findFunctionWarnings(module, globalRefs, warnings, suppressions) :
    """
    @type  module:     L{pychecker.checker.PyCheckerModule}
    @param globalRefs: dict of token alias -> full name of token aliases
                       that have been used ?
    @type  globalRefs: dict of str -> str
    """
    for func in module.functions.values() :
        func_code = func.function.func_code
        utils.debug("function:", func_code)

        name = '%s.%s' % (module.moduleName, func.function.__name__)
        suppress = getSuppression(name, suppressions, warnings)
        if cfg().noDocFunc and func.function.__doc__ == None :
            err = msgs.NO_FUNC_DOC % func.function.__name__
            # FIXME: is there a good reason why this passes func_code as line ?
            warnings.append(Warning(module.filename(), func_code, err))

        _checkNoSelfArg(func, warnings)
        _updateFunctionWarnings(module, func, None, warnings, globalRefs)
        if suppress is not None :
            utils.popConfig()
Example #16
0
def find(moduleList, initialCfg, suppressions=None):
    "Return a list of warnings found in the module list"

    if suppressions is None :
        suppressions = {}, {}

    utils.initConfig(initialCfg)
    utils.debug('Finding warnings in %d modules' % len(moduleList))

    warnings = []
    before = 0

    for module in moduleList :
        if module.moduleName in cfg().blacklist :
            continue

        modSuppress = getSuppression(module.moduleName, suppressions, warnings)
        globalRefs, classCodes = {}, {}

        # mainCode can be null if there was a syntax error
        if module.mainCode != None :
            utils.debug("module:", module)
            before = len(warnings)
            funcInfo = _updateFunctionWarnings(module, module.mainCode,
                                               None, warnings, globalRefs, 1)

            if before != len(warnings):
                utils.debug("module: %r __main__ triggered %d warnings", module,
                    len(warnings) - before)

            for code in funcInfo[1] :
                classCodes[code.co_name] = code

        before = len(warnings)
        _findFunctionWarnings(module, globalRefs, warnings, suppressions)
        if before != len(warnings):
            utils.debug("module: %r functions triggered %d warnings", module,
                len(warnings) - before)

        before = len(warnings)
        for c in module.classes.values():
            _findClassWarnings(module, c, classCodes.get(c.name),
                               globalRefs, warnings, suppressions)
        if before != len(warnings):
            utils.debug("module: %r classes triggered %d warnings", module,
                len(warnings) - before)

        if cfg().noDocModule and \
           module.module != None and module.module.__doc__ == None:
            warnings.append(Warning(module.filename(), 1, msgs.NO_MODULE_DOC))
            utils.debug("module: %r module doc triggered 1 warning")

        before = len(warnings)
        if cfg().allVariablesUsed or cfg().privateVariableUsed:
            prefix = None
            if not cfg().allVariablesUsed:
                prefix = "_"
            for ignoreVar in cfg().variablesToIgnore + cfg().unusedNames:
                globalRefs[ignoreVar] = ignoreVar
            warnings.extend(_getUnused(module, globalRefs, module.variables,
                                       msgs.VAR_NOT_USED, prefix))
        if before != len(warnings):
            utils.debug("module: %r unused variables triggered %d warnings",
                module, len(warnings) - before)

        before = len(warnings)
        if cfg().importUsed:
            if module.moduleName != utils.INIT or cfg().packageImportUsed:
                # always ignore readline module, if [raw_]input() is used
                if globalRefs.has_key('input') or \
                   globalRefs.has_key('raw_input'):
                    globalRefs['readline'] = 0
                warnings.extend(_getUnused(module, globalRefs, module.modules,
                                           msgs.IMPORT_NOT_USED))
        if before != len(warnings):
            utils.debug("module: %r unused imports triggered %d warnings",
                module, len(warnings) - before)

        # we have to do this here, b/c checkFunction doesn't popConfig for
        # classes this allows us to have __pychecker__ apply to all methods
        # when defined at class scope
        if module.mainCode != None:
            utils.popConfig()
        if modSuppress is not None:
            utils.popConfig()

    std_lib = None
    if cfg().ignoreStandardLibrary:
        std_lib = getStandardLibraries()

    ret = removeWarnings(warnings, getBlackList(cfg().blacklist), std_lib,
                          cfg())
    utils.debug('Found %d warnings in %d modules' % (len(ret), len(moduleList)))
    return ret
Example #17
0
def _findClassWarnings(module, c, class_code,
                       globalRefs, warnings, suppressions) :
    utils.debug("class:", class_code)
    try:
        className = utils.safestr(c.classObject)
    except TypeError:
        # goofy __getattr__
        return
    classSuppress = getSuppression(className, suppressions, warnings)
    baseClasses = c.allBaseClasses()
    for base in baseClasses :
        baseModule = utils.safestr(base)
        if '.' in baseModule :
            # make sure we handle import x.y.z
            packages = string.split(baseModule, '.')
            baseModuleDir = string.join(packages[:-1], '.')
            globalRefs[baseModuleDir] = baseModule

    # handle class variables
    if class_code is not None :
        func = function.create_fake(c.name, class_code)
        _updateFunctionWarnings(module, func, c, warnings, globalRefs, 0, 1)

    filename = module.filename()
    func_code = None
    for method in c.methods.values() :
        if method == None :
            continue
        func_code = method.function.func_code
        utils.debug("class %s: method:" % className, func_code)

        try:
            name = utils.safestr(c.classObject) + '.' + method.function.func_name
        except AttributeError:
            # func_name may not exist
            continue
        methodSuppress = getSuppression(name, suppressions, warnings)

        if cfg().checkSpecialMethods:
            funcname = method.function.func_name
            if funcname[:2] == '__' == funcname[-2:] and \
               funcname != '__init__':
                err = None
                argCount = python.SPECIAL_METHODS.get(funcname, -1)
                if argCount != -1:
                    # if the args are None, it can be any # of args
                    if argCount is not None:
                        minArgs = maxArgs = argCount
                        err = CodeChecks.getFunctionArgErr(funcname,
                                     func_code.co_argcount, minArgs, maxArgs)
                else:
                    err = msgs.NOT_SPECIAL_METHOD % funcname

                if err is not None:
                    warnings.append(Warning(filename, func_code, err))
                
        if cfg().checkOverridenMethods :
            _checkOverridenMethods(method.function, baseClasses, warnings)

        if cfg().noDocFunc and method.function.__doc__ == None :
            err = msgs.NO_FUNC_DOC % method.function.__name__
            # FIXME: is there a good reason why this passes func_code as line ?
            warnings.append(Warning(filename, func_code, err))

        _checkSelfArg(method, warnings)
        tmpModule = _getModuleFromFilename(module, func_code.co_filename)
        funcInfo = _updateFunctionWarnings(tmpModule, method, c, warnings, globalRefs)
        if func_code.co_name == utils.INIT :
            # this is a constructor
            if utils.INIT in dir(c.classObject) :
                warns = _checkBaseClassInit(filename, c, func_code, funcInfo)
                warnings.extend(warns)
            elif cfg().initDefinedInSubclass :
                err = msgs.NO_INIT_IN_SUBCLASS % c.name
                warnings.append(Warning(filename, c.getFirstLine(), err))
        if methodSuppress is not None :
            utils.popConfig()

    if c.memberRefs and cfg().membersUsed :
        memberList = c.memberRefs.keys()
        memberList.sort()
        err = msgs.UNUSED_MEMBERS % (string.join(memberList, ', '), c.name)
        warnings.append(Warning(filename, c.getFirstLine(), err))

    try:
        newStyleClass = issubclass(c.classObject, object)
    except TypeError:
        # FIXME: perhaps this should warn b/c it may be a class???
        newStyleClass = 0

    slots = c.statics.get('__slots__')
    if slots is not None and cfg().slots:
        lineNum = c.lineNums['__slots__']
        if not newStyleClass:
            err = msgs.USING_SLOTS_IN_CLASSIC_CLASS % c.name
            warnings.append(Warning(filename, lineNum, err))
        elif cfg().emptySlots:
            try:
                if len(slots.data) == 0:
                    err = msgs.EMPTY_SLOTS % c.name
                    warnings.append(Warning(filename, lineNum, err))
            except AttributeError:
                # happens when slots is an instance of a class w/o __len__
                pass

    if not newStyleClass and property is not None and cfg().classicProperties:
        for static in c.statics.keys():
            if type(getattr(c.classObject, static, None)) == property:
                err = msgs.USING_PROPERTIES_IN_CLASSIC_CLASS % (static, c.name)
                warnings.append(Warning(filename, c.lineNums[static], err))

    coerceMethod = c.methods.get('__coerce__')
    if newStyleClass and coerceMethod:
        lineNum = coerceMethod.function.func_code.co_firstlineno
        err = msgs.USING_COERCE_IN_NEW_CLASS % c.name
        warnings.append(Warning(filename, lineNum, err))

    for newClassMethodName in python.NEW_STYLE_CLASS_METHODS:
        newClassMethod = c.methods.get(newClassMethodName)
        if not newStyleClass and newClassMethod:
            lineNum = newClassMethod.function.func_code.co_firstlineno
            err = msgs.USING_NEW_STYLE_METHOD_IN_OLD_CLASS % (newClassMethodName, c.name)
            warnings.append(Warning(filename, lineNum, err))

    if cfg().noDocClass and c.classObject.__doc__ == None :
        method = c.methods.get(utils.INIT, None)
        if method != None :
            func_code = method.function.func_code
        # FIXME: check to make sure this is in our file,
        #        not a base class file???
        err = msgs.NO_CLASS_DOC % c.classObject.__name__
        warnings.append(Warning(filename, func_code, err))

    # we have to do this here, b/c checkFunction doesn't popConfig for classes
    # this allows us to have __pychecker__ apply to all methods
    # when defined at class scope
    if class_code is not None :
        utils.popConfig()

    if classSuppress is not None :
        utils.popConfig()
Example #18
0
def removeWarnings(warnings, blacklist, std_lib, cfg):
    """
    @param blacklist: list of absolute paths not to warn for
    @type  blacklist: str
    @param std_lib:   list of standard library directories
    @type  std_lib:   list of str or None
    """
    utils.debug('filtering %d warnings with blacklist', len(warnings))

    if std_lib is not None:
        std_lib = [normalize_path(p) for p in std_lib]
    for index in range(len(warnings) - 1, -1, -1):
        filename = normalize_path(warnings[index].file)
        # the blacklist contains paths to packages and modules we do not
        # want warnings for
        # when we find a match, make sure we continue the warnings for loop
        found = False
        for path in blacklist:
            if not found and filename.startswith(path):
                found = True
                del warnings[index]
        if found:
            continue
        if std_lib:
            found = False
            for path in std_lib:
                if not found and utils.startswith(filename, path) :
                    found = True
                    del warnings[index]
            if found:
                continue
        elif cfg.only:
            # ignore files not specified on the cmd line if requested
            if os.path.abspath(filename) not in cfg.files:
                del warnings[index]
                continue

        # filter by warning/error level if requested
        if cfg.level and warnings[index].level < cfg.level:
            del warnings[index]

    if cfg.limit:
        # sort by severity first, then normal sort (by file/line)
        warnings.sort(lambda a, b: cmp(a.level, b.level) or cmp(a, b))

        # strip duplicates
        lastWarning = None
        for index in range(len(warnings)-1, -1, -1):
            warning = warnings[index]

            # remove duplicate warnings
            if lastWarning is not None and cmp(lastWarning, warning) == 0:
                del warnings[index]
            else:
                lastWarning = warning

        num_ignored = len(warnings) - cfg.limit
        if num_ignored > 0:
            del warnings[:-cfg.limit]
            msg = msgs.TOO_MANY_WARNINGS % num_ignored
            warnings.append(Warning('', 0, msg))

    utils.debug('kept %d warnings with blacklist', len(warnings))

    return warnings
Example #19
0
def _check(files, cfg=None, suppressions=None, printProcessing=False):
    # snapshot modules before and after processing, so that we only warn
    # about the modules loaded because of these files.
    # preferable to clearing the loaded modules because we don't have to
    # reprocess previously handled modules
    beforePCModules = getAllPCModules()
    beforeModules = dict(sys.modules.items())
    utils.initConfig(cfg)

    utils.debug('main: Checking %d files', len(files))
    utils.debug('main: Finding import warnings')
    importWarnings = processFiles(
        files, cfg, printProcessing and _print_processing or None)
    utils.debug('main: Found %d import warnings' % len(importWarnings))
    utils.debug('main: %d modules in sys.modules' % len(sys.modules.keys()))

    fixupBuiltinModules()

    afterPCModules = getAllPCModules()

    newPCModules = afterPCModules[:]
    for m in beforePCModules:
        if m in newPCModules:
            newPCModules.remove(m)

    newModules = dict(sys.modules.items())
    for k, v in beforeModules.items():
        if k in newModules:
            del newModules[k]

    if cfg.printParse:
        for module in newPCModules:
            printer.module(module)
    utils.debug('main: %d Pychecker modules and %d python modules loaded',
                len(newPCModules), len(newModules))

    # remove all sys.modules suspected of being sibling imports; they now
    # pollute the global namespace of sys.modules
    for k, v in newModules.items():
        if v and _mightBeSiblingModule(v):
            utils.debug('main: unloading python module %s', v)
            del sys.modules[k]

    utils.debug('main: Finding warnings')
    # suppressions is a tuple of suppressions, suppressionRegexs dicts
    warnings = warn.find(newPCModules, cfg, suppressions)

    utils.debug('main: Found %d warnings in %d files and %d modules',
                len(importWarnings) + len(warnings), len(files),
                len(newPCModules))

    # FIXME: any way to assert we are popping the one we pushed ?
    utils.popConfig()

    return importWarnings + warnings
Example #20
0
def find(moduleList, initialCfg, suppressions=None):
    "Return a list of warnings found in the module list"

    if suppressions is None :
        suppressions = {}, {}

    utils.initConfig(initialCfg)
    utils.debug('Finding warnings in %d modules' % len(moduleList))

    warnings = []
    before = 0

    for module in moduleList :
        if module.moduleName in cfg().blacklist :
            continue

        modSuppress = getSuppression(module.moduleName, suppressions, warnings)
        globalRefs, classCodes = {}, {}

        # mainCode can be null if there was a syntax error
        if module.mainCode != None :
            utils.debug("module:", module)
            before = len(warnings)
            funcInfo = _updateFunctionWarnings(module, module.mainCode,
                                               None, warnings, globalRefs, 1)

            if before != len(warnings):
                utils.debug("module: %r __main__ triggered %d warnings", module,
                    len(warnings) - before)

            for code in funcInfo[1] :
                classCodes[code.co_name] = code

        before = len(warnings)
        _findFunctionWarnings(module, globalRefs, warnings, suppressions)
        if before != len(warnings):
            utils.debug("module: %r functions triggered %d warnings", module,
                len(warnings) - before)

        before = len(warnings)
        for c in module.classes.values():
            _findClassWarnings(module, c, classCodes.get(c.name),
                               globalRefs, warnings, suppressions)
        if before != len(warnings):
            utils.debug("module: %r classes triggered %d warnings", module,
                len(warnings) - before)

        if cfg().noDocModule and \
           module.module != None and module.module.__doc__ == None:
            warnings.append(Warning(module.filename(), 1, msgs.NO_MODULE_DOC))
            utils.debug("module: %r module doc triggered 1 warning")

        before = len(warnings)
        if cfg().allVariablesUsed or cfg().privateVariableUsed:
            prefix = None
            if not cfg().allVariablesUsed:
                prefix = "_"
            for ignoreVar in cfg().variablesToIgnore + cfg().unusedNames:
                globalRefs[ignoreVar] = ignoreVar
            warnings.extend(_getUnused(module, globalRefs, module.variables,
                                       msgs.VAR_NOT_USED, prefix))
        if before != len(warnings):
            utils.debug("module: %r unused variables triggered %d warnings",
                module, len(warnings) - before)

        before = len(warnings)
        if cfg().importUsed:
            if module.moduleName != utils.INIT or cfg().packageImportUsed:
                # always ignore readline module, if [raw_]input() is used
                if globalRefs.has_key('input') or \
                   globalRefs.has_key('raw_input'):
                    globalRefs['readline'] = 0
                warnings.extend(_getUnused(module, globalRefs, module.modules,
                                           msgs.IMPORT_NOT_USED))
        if before != len(warnings):
            utils.debug("module: %r unused imports triggered %d warnings",
                module, len(warnings) - before)

        # we have to do this here, b/c checkFunction doesn't popConfig for
        # classes this allows us to have __pychecker__ apply to all methods
        # when defined at class scope
        if module.mainCode != None:
            utils.popConfig()
        if modSuppress is not None:
            utils.popConfig()

    std_lib = None
    if cfg().ignoreStandardLibrary:
        std_lib = getStandardLibraries()

    ret = removeWarnings(warnings, getBlackList(cfg().blacklist), std_lib,
                          cfg())
    utils.debug('Found %d warnings in %d modules' % (len(ret), len(moduleList)))
    return ret
Example #21
0
        argv = argv[:1] + string.split(command_line) + argv[2:]
 
    global _cfg
    _cfg, files, suppressions = Config.setupFromArgs(argv[1:])
    utils.initConfig(_cfg)
    if not files :
        return 0

    # Now that we've got the args, update the list of evil C objects
    for evil_doer in _cfg.evil:
        pcmodules.EVIL_C_OBJECTS[evil_doer] = None

    # insert this here, so we find files in the local dir before std library
    sys.path.insert(0, '')

    utils.debug('main: Finding import warnings')
    importWarnings = processFiles(files, _cfg, _print_processing)
    utils.debug('main: Found %d import warnings' % len(importWarnings))

    fixupBuiltinModules()
    if _cfg.printParse :
        for module in getAllModules() :
            printer.module(module)

    utils.debug('main: Finding warnings')
    # suppressions is a tuple of suppressions, suppressionRegexs dicts
    warnings = warn.find(getAllModules(), _cfg, suppressions)
    utils.debug('main: Found %d warnings' % len(warnings))

    if not _cfg.quiet :
        print "\nWarnings...\n"
Example #22
0
def _findClassWarnings(module, c, class_code,
                       globalRefs, warnings, suppressions) :
    try:
        className = utils.safestr(c.classObject)
    except TypeError:
        # goofy __getattr__
        return
    classSuppress = getSuppression(className, suppressions, warnings)
    baseClasses = c.allBaseClasses()
    for base in baseClasses :
        baseModule = utils.safestr(base)
        if '.' in baseModule :
            # make sure we handle import x.y.z
            packages = string.split(baseModule, '.')
            baseModuleDir = string.join(packages[:-1], '.')
            globalRefs[baseModuleDir] = baseModule

    # handle class variables
    if class_code is not None :
        func = function.create_fake(c.name, class_code)
        _updateFunctionWarnings(module, func, c, warnings, globalRefs, 0, 1)

    filename = module.filename()
    func_code = None
    for method in c.methods.values() :
        if method == None :
            continue
        func_code = method.function.func_code
        utils.debug("method:", func_code)

        try:
            name = utils.safestr(c.classObject) + '.' + method.function.func_name
        except AttributeError:
            # func_name may not exist
            continue
        methodSuppress = getSuppression(name, suppressions, warnings)

        if cfg().checkSpecialMethods:
            funcname = method.function.func_name
            if funcname[:2] == '__' == funcname[-2:] and \
               funcname != '__init__':
                err = None
                argCount = python.SPECIAL_METHODS.get(funcname, -1)
                if argCount != -1:
                    # if the args are None, it can be any # of args
                    if argCount is not None:
                        minArgs = maxArgs = argCount
                        err = CodeChecks.getFunctionArgErr(funcname,
                                     func_code.co_argcount, minArgs, maxArgs)
                else:
                    err = msgs.NOT_SPECIAL_METHOD % funcname

                if err is not None:
                    warnings.append(Warning(filename, func_code, err))
                
        if cfg().checkOverridenMethods :
            _checkOverridenMethods(method.function, baseClasses, warnings)

        if cfg().noDocFunc and method.function.__doc__ == None :
            err = msgs.NO_FUNC_DOC % method.function.__name__
            # FIXME: is there a good reason why this passes func_code as line ?
            warnings.append(Warning(filename, func_code, err))

        _checkSelfArg(method, warnings)
        tmpModule = _getModuleFromFilename(module, func_code.co_filename)
        funcInfo = _updateFunctionWarnings(tmpModule, method, c, warnings, globalRefs)
        if func_code.co_name == utils.INIT :
            # this is a constructor
            if utils.INIT in dir(c.classObject) :
                warns = _checkBaseClassInit(filename, c, func_code, funcInfo)
                warnings.extend(warns)
            elif cfg().initDefinedInSubclass :
                err = msgs.NO_INIT_IN_SUBCLASS % c.name
                warnings.append(Warning(filename, c.getFirstLine(), err))
        if methodSuppress is not None :
            utils.popConfig()

    if c.memberRefs and cfg().membersUsed :
        memberList = c.memberRefs.keys()
        memberList.sort()
        err = msgs.UNUSED_MEMBERS % (string.join(memberList, ', '), c.name)
        warnings.append(Warning(filename, c.getFirstLine(), err))

    try:
        newStyleClass = issubclass(c.classObject, object)
    except TypeError:
        # FIXME: perhaps this should warn b/c it may be a class???
        newStyleClass = 0

    slots = c.statics.get('__slots__')
    if slots is not None and cfg().slots:
        lineNum = c.lineNums['__slots__']
        if not newStyleClass:
            err = msgs.USING_SLOTS_IN_CLASSIC_CLASS % c.name
            warnings.append(Warning(filename, lineNum, err))
        elif cfg().emptySlots:
            try:
                if len(slots.data) == 0:
                    err = msgs.EMPTY_SLOTS % c.name
                    warnings.append(Warning(filename, lineNum, err))
            except AttributeError:
                # happens when slots is an instance of a class w/o __len__
                pass

    if not newStyleClass and property is not None and cfg().classicProperties:
        for static in c.statics.keys():
            if type(getattr(c.classObject, static, None)) == property:
                err = msgs.USING_PROPERTIES_IN_CLASSIC_CLASS % (static, c.name)
                warnings.append(Warning(filename, c.lineNums[static], err))

    coerceMethod = c.methods.get('__coerce__')
    if newStyleClass and coerceMethod:
        lineNum = coerceMethod.function.func_code.co_firstlineno
        err = msgs.USING_COERCE_IN_NEW_CLASS % c.name
        warnings.append(Warning(filename, lineNum, err))

    for newClassMethodName in python.NEW_STYLE_CLASS_METHODS:
        newClassMethod = c.methods.get(newClassMethodName)
        if not newStyleClass and newClassMethod:
            lineNum = newClassMethod.function.func_code.co_firstlineno
            err = msgs.USING_NEW_STYLE_METHOD_IN_OLD_CLASS % (newClassMethodName, c.name)
            warnings.append(Warning(filename, lineNum, err))

    if cfg().noDocClass and c.classObject.__doc__ == None :
        method = c.methods.get(utils.INIT, None)
        if method != None :
            func_code = method.function.func_code
        # FIXME: check to make sure this is in our file,
        #        not a base class file???
        err = msgs.NO_CLASS_DOC % c.classObject.__name__
        warnings.append(Warning(filename, func_code, err))

    # we have to do this here, b/c checkFunction doesn't popConfig for classes
    # this allows us to have __pychecker__ apply to all methods
    # when defined at class scope
    if class_code is not None :
        utils.popConfig()

    if classSuppress is not None :
        utils.popConfig()
Example #23
0
def removeWarnings(warnings, blacklist, std_lib, cfg):
    """
    @param blacklist: list of absolute paths not to warn for
    @type  blacklist: str
    @param std_lib:   list of standard library directories
    @type  std_lib:   list of str or None
    """
    utils.debug('filtering %d warnings with blacklist', len(warnings))

    if std_lib is not None:
        std_lib = [normalize_path(p) for p in std_lib]
    for index in range(len(warnings) - 1, -1, -1):
        filename = normalize_path(warnings[index].file)
        # the blacklist contains paths to packages and modules we do not
        # want warnings for
        # when we find a match, make sure we continue the warnings for loop
        found = False
        for path in blacklist:
            if not found and filename.startswith(path):
                found = True
                del warnings[index]
        if found:
            continue
        if std_lib:
            found = False
            for path in std_lib:
                if not found and utils.startswith(filename, path) :
                    found = True
                    del warnings[index]
            if found:
                continue
        elif cfg.only:
            # ignore files not specified on the cmd line if requested
            if os.path.abspath(filename) not in cfg.files:
                del warnings[index]
                continue

        # filter by warning/error level if requested
        if cfg.level and warnings[index].level < cfg.level:
            del warnings[index]

    if cfg.limit:
        # sort by severity first, then normal sort (by file/line)
        warnings.sort(lambda a, b: cmp(a.level, b.level) or cmp(a, b))

        # strip duplicates
        lastWarning = None
        for index in range(len(warnings)-1, -1, -1):
            warning = warnings[index]

            # remove duplicate warnings
            if lastWarning is not None and cmp(lastWarning, warning) == 0:
                del warnings[index]
            else:
                lastWarning = warning

        num_ignored = len(warnings) - cfg.limit
        if num_ignored > 0:
            del warnings[:-cfg.limit]
            msg = msgs.TOO_MANY_WARNINGS % num_ignored
            warnings.append(Warning('', 0, msg))

    utils.debug('kept %d warnings with blacklist', len(warnings))

    return warnings
Example #24
0
        argv = argv[:1] + string.split(command_line) + argv[2:]

    global _cfg
    _cfg, files, suppressions = Config.setupFromArgs(argv[1:])
    utils.initConfig(_cfg)
    if not files:
        return 0

    # Now that we've got the args, update the list of evil C objects
    for evil_doer in _cfg.evil:
        pcmodules.EVIL_C_OBJECTS[evil_doer] = None

    # insert this here, so we find files in the local dir before std library
    sys.path.insert(0, '')

    utils.debug('main: Finding import warnings')
    importWarnings = processFiles(files, _cfg, _print_processing)
    utils.debug('main: Found %d import warnings' % len(importWarnings))

    fixupBuiltinModules()
    if _cfg.printParse:
        for module in getAllModules():
            printer.module(module)

    utils.debug('main: Finding warnings')
    # suppressions is a tuple of suppressions, suppressionRegexs dicts
    warnings = warn.find(getAllModules(), _cfg, suppressions)
    utils.debug('main: Found %d warnings' % len(warnings))

    if not _cfg.quiet:
        print "\nWarnings...\n"
Example #25
0
def _check(files, cfg=None, suppressions=None, printProcessing=False):
    # snapshot modules before and after processing, so that we only warn
    # about the modules loaded because of these files.
    # preferable to clearing the loaded modules because we don't have to
    # reprocess previously handled modules
    beforePCModules = getAllPCModules()
    beforeModules = dict(sys.modules.items())
    utils.initConfig(cfg)

    utils.debug('main: Checking %d files', len(files))
    utils.debug('main: Finding import warnings')
    importWarnings = processFiles(files, cfg,
        printProcessing and _print_processing or None)
    utils.debug('main: Found %d import warnings' % len(importWarnings))
    utils.debug('main: %d modules in sys.modules' % len(sys.modules.keys()))

    fixupBuiltinModules()

    afterPCModules = getAllPCModules()

    newPCModules = afterPCModules[:]
    for m in beforePCModules:
        if m in newPCModules:
            newPCModules.remove(m)

    newModules = dict(sys.modules.items())
    for k, v in beforeModules.items():
        if k in newModules:
            del newModules[k]

    if cfg.printParse :
        for module in newPCModules:
            printer.module(module)
    utils.debug('main: %d Pychecker modules and %d python modules loaded',
        len(newPCModules), len(newModules))

    # remove all sys.modules suspected of being sibling imports; they now
    # pollute the global namespace of sys.modules
    for k, v in newModules.items():
        if v and _mightBeSiblingModule(v):
            utils.debug('main: unloading python module %s', v)
            del sys.modules[k]

    utils.debug('main: Finding warnings')
    # suppressions is a tuple of suppressions, suppressionRegexs dicts
    warnings = warn.find(newPCModules, cfg, suppressions)

    utils.debug('main: Found %d warnings in %d files and %d modules',
        len(importWarnings) + len(warnings), len(files), len(newPCModules))

    # FIXME: any way to assert we are popping the one we pushed ?
    utils.popConfig()

    return importWarnings + warnings