Ejemplo n.º 1
0
def processFiles(files, cfg=None, pre_process_cb=None):
    # 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__()

    warnings = []
    utils.initConfig(_cfg)
    for file, (moduleName, moduleDir) in zip(files, getModules(files)):
        if callable(pre_process_cb):
            pre_process_cb("module %s (%s)" % (moduleName, file))
        oldsyspath = sys.path[:]
        sys.path.insert(0, moduleDir)
        module = PyCheckerModule(moduleName, moduleDir=moduleDir)
        if not module.load():
            w = Warning(module.filename(), 1,
                        msgs.Internal("NOT PROCESSED UNABLE TO IMPORT"))
            warnings.append(w)
        sys.path = oldsyspath
    utils.popConfig()
    return warnings
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):
            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.º 4
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.º 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) :
            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.º 6
0
def processFiles(files, cfg=None, pre_process_cb=None):
    # 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()

    warnings = []
    utils.initConfig(_cfg)
    for moduleName, filename in getModules(files):
        if callable(pre_process_cb):
            pre_process_cb(moduleName)
        module = Module(moduleName, fullpath=filename)

        # reload the given module, otherwise won't get new syntax errors.
        sysModule = sys.modules.get(moduleName)
        if sysModule:
            try:
                reload(sysModule)
            except:
                pass

        module.load(warnings)
    utils.popConfig()
    return warnings
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) :
            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 processFiles(files, cfg = None, pre_process_cb = None) :
    # 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__()

    warnings = []
    utils.initConfig(_cfg)
    for file, (moduleName, moduleDir) in zip(files, getModules(files)) :
        if callable(pre_process_cb) :
            pre_process_cb("module %s (%s)" % (moduleName, file))
        oldsyspath = sys.path[:]
        sys.path.insert(0, moduleDir)
        module = PyCheckerModule(moduleName, moduleDir=moduleDir)
        if not module.load() :
            w = Warning(module.filename(), 1,
                        msgs.Internal("NOT PROCESSED UNABLE TO IMPORT"))
            warnings.append(w)
        sys.path = oldsyspath
    utils.popConfig()
    return warnings
Ejemplo n.º 9
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.º 10
0
def processFiles(files, cfg = None, pre_process_cb = None) :
    # 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()

    warnings = []
    utils.initConfig(_cfg)
    for moduleName, filename in getModules(files) :
        if callable(pre_process_cb) :
            pre_process_cb(moduleName)
        module = Module(moduleName, fullpath = filename)

        # reload the given module, otherwise won't get new syntax errors.
        sysModule = sys.modules.get(moduleName)
        if sysModule:
            try:
                reload(sysModule)
            except:
                pass
                
        module.load(warnings)
    utils.popConfig()
    return warnings
Ejemplo n.º 11
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.º 12
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.º 13
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)

    warnings = []
    for module in moduleList :
        if module.moduleName in cfg().blacklist :
            continue

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

        # main_code can be null if there was a syntax error
        if module.main_code != None :
            funcInfo = _updateFunctionWarnings(module, module.main_code,
                                               None, warnings, globalRefs, 1)
            for code in funcInfo[1] :
                classCodes[code.co_name] = code

        _findFunctionWarnings(module, globalRefs, warnings, suppressions)

        for c in module.classes.values() :
            _findClassWarnings(module, c, classCodes.get(c.name),
                               globalRefs, warnings, suppressions)

        if cfg().noDocModule and \
           module.module != None and module.module.__doc__ == None :
            warnings.append(Warning(module.filename(), 1, msgs.NO_MODULE_DOC))

        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 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 module.main_code != None :
            utils.popConfig()
        if modSuppress is not None :
            utils.popConfig()

    std_lib = None
    if cfg().ignoreStandardLibrary :
        std_lib = getStandardLibraries()
    return removeWarnings(warnings, getBlackList(cfg().blacklist), std_lib,
                          cfg())
Ejemplo n.º 14
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
Ejemplo n.º 15
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
Ejemplo n.º 16
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
Ejemplo n.º 17
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
Ejemplo n.º 18
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
Ejemplo n.º 19
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()
Ejemplo n.º 20
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()
Ejemplo n.º 21
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
Ejemplo n.º 22
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()
Ejemplo n.º 23
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.º 24
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()
Ejemplo n.º 25
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.º 26
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.º 27
0
def processFiles(files, cfg=None, pre_process_cb=None):
    # 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()

    warnings = []
    utils.initConfig(_cfg)
    for moduleName in getModules(files):
        if callable(pre_process_cb):
            pre_process_cb(moduleName)
        module = PyCheckerModule(moduleName)
        if not module.load():
            w = Warning(module.filename(), 1,
                        msgs.Internal("NOT PROCESSED UNABLE TO IMPORT"))
            warnings.append(w)
    utils.popConfig()
    return warnings
Ejemplo n.º 28
0
def processFiles(files, cfg = None, pre_process_cb = None) :
    # 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()

    warnings = []
    utils.initConfig(_cfg)
    for moduleName in getModules(files) :
        if callable(pre_process_cb) :
            pre_process_cb(moduleName)
        module = PyCheckerModule(moduleName)
        if not module.load() :
            w = Warning(module.filename(), 1,
                        msgs.Internal("NOT PROCESSED UNABLE TO IMPORT"))
            warnings.append(w)
    utils.popConfig()
    return warnings
Ejemplo n.º 29
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()
Ejemplo n.º 30
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)
Ejemplo n.º 31
0
def _updateSuppressions(suppress, warnings) :
    if not utils.updateCheckerArgs(suppress, 'suppressions', 0, warnings) :
        utils.popConfig()
        raise _SuppressionError
Ejemplo n.º 32
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.º 33
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
Ejemplo n.º 34
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
Ejemplo n.º 35
0
def _updateSuppressions(suppress, warnings) :
    if not utils.updateCheckerArgs(suppress, 'suppressions', 0, warnings) :
        utils.popConfig()
        raise _SuppressionError
Ejemplo n.º 36
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.º 37
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)

    warnings = []
    for module in moduleList:
        if module.moduleName in cfg().blacklist:
            continue

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

        # main_code can be null if there was a syntax error
        if module.main_code != None:
            funcInfo = _updateFunctionWarnings(module, module.main_code, None,
                                               warnings, globalRefs, 1)
            for code in funcInfo[1]:
                classCodes[code.co_name] = code

        _findFunctionWarnings(module, globalRefs, warnings, suppressions)

        for c in module.classes.values():
            _findClassWarnings(module, c, classCodes.get(c.name), globalRefs,
                               warnings, suppressions)

        if cfg().noDocModule and \
           module.module != None and module.module.__doc__ == None :
            warnings.append(Warning(module.filename(), 1, msgs.NO_MODULE_DOC))

        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 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 module.main_code != None:
            utils.popConfig()
        if modSuppress is not None:
            utils.popConfig()

    std_lib = None
    if cfg().ignoreStandardLibrary:
        std_lib = getStandardLibraries()
    return removeWarnings(warnings, getBlackList(cfg().blacklist), std_lib,
                          cfg())
Ejemplo n.º 38
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()