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