📄 checker.py
字号:
#!/usr/bin/env python# Copyright (c) 2001-2004, MetaSlash Inc. All rights reserved."""Copyright notice from pychecker: Copyright (c) 2000-2001, MetaSlash Inc.All rights reserved.Redistribution and use in source and binary forms, with or withoutmodification, are permitted provided that the following conditions aremet: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither name of MetaSlash Inc. nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOTLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FORA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS ORCONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, ORPROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDINGNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THISSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.""""""Check python source code files for possible errors and print warningsContact Info: http://pychecker.sourceforge.net/ pychecker-list@lists.sourceforge.net"""import stringimport typesimport sysimport impimport osimport globimport tracebackimport reimport wx_ = wx.GetTranslation# see __init__.py for meaning, this must match the version thereLOCAL_MAIN_VERSION = 1def setupNamespace(path) : # remove pychecker if it's the first component, it needs to be last if sys.path[0][-9:] == 'pychecker' : del sys.path[0] # make sure pychecker is last in path, so we can import checker_path = os.path.dirname(os.path.dirname(path)) if checker_path not in sys.path : sys.path.append(checker_path)if __name__ == '__main__' : setupNamespace(sys.argv[0])from pychecker import utilsfrom pychecker import printerfrom pychecker import warnfrom pychecker import OPfrom pychecker import Configfrom pychecker import functionfrom pychecker.Warning import Warning# Globals for storing a dictionary of info about modules and classes_allModules = {}_cfg = None# Constants_DEFAULT_MODULE_TOKENS = ('__builtins__', '__doc__', '__file__', '__name__', '__path__')_DEFAULT_CLASS_TOKENS = ('__doc__', '__name__', '__module__')_VERSION_MISMATCH_ERROR = '''There seem to be two versions of PyChecker being used.One is probably in python/site-packages, the other in a local directory.If you want to run the local version, you must remove the versionfrom site-packages. Or you can install the current versionby doing python setup.py install.'''def cfg() : return utils.cfg()def _flattenList(list) : "Returns a list which contains no lists" new_list = [] for element in list : if type(element) == types.ListType : new_list.extend(_flattenList(element)) else : new_list.append(element) return new_listdef getModules(arg_list) : "Returns a list of module names that can be imported" global _output new_arguments = [] for arg in arg_list : # is this a wildcard filespec? (necessary for windows) if '*' in arg or '?' in arg or '[' in arg : arg = glob.glob(arg) new_arguments.append(arg) PY_SUFFIXES = ['.py'] PY_SUFFIX_LENS = [3] if _cfg.quixote: PY_SUFFIXES.append('.ptl') PY_SUFFIX_LENS.append(4) modules = [] for arg in _flattenList(new_arguments) : fullpath = arg # is it a .py file? for suf, suflen in zip(PY_SUFFIXES, PY_SUFFIX_LENS): if len(arg) > suflen and arg[-suflen:] == suf: arg_dir = os.path.dirname(arg) if arg_dir and not os.path.exists(arg) : txt = _('File or pathname element does not exist: "%s"') % arg _output.AddLines(txt) continue module_name = os.path.basename(arg)[:-suflen] if arg_dir not in sys.path : sys.path.insert(0, arg_dir) arg = module_name modules.append((arg, fullpath)) return modulesdef _q_file(f): # crude hack!!! # imp.load_module requires a real file object, so we can't just # fiddle def lines and yield them import tempfile fd, newfname = tempfile.mkstemp(suffix=".py", text=True) newf = os.fdopen(fd, 'r+') os.unlink(newfname) for line in f: mat = re.match(r'(\s*def\s+\w+\s*)\[(html|plain)\](.*)', line) if mat is None: newf.write(line) else: newf.write(mat.group(1)+mat.group(3)+'\n') newf.seek(0) return newfdef _q_find_module(p, path): if not _cfg.quixote: return imp.find_module(p, path) else: for direc in path: try: return imp.find_module(p, [direc]) except ImportError: f = os.path.join(direc, p+".ptl") if os.path.exists(f): return _q_file(file(f)), f, ('.ptl', 'U', 1)def _findModule(name) : """Returns the result of an imp.find_module(), ie, (file, filename, smt) name can be a module or a package name. It is *not* a filename.""" path = sys.path[:] packages = string.split(name, '.') for p in packages : # smt = (suffix, mode, type) file, filename, smt = _q_find_module(p, path) if smt[-1] == imp.PKG_DIRECTORY : try : # package found - read path info from init file m = imp.load_module(p, file, filename, smt) finally : if file is not None : file.close() # importing xml plays a trick, which replaces itself with _xmlplus # both have subdirs w/same name, but different modules in them # we need to choose the real (replaced) version if m.__name__ != p : try : file, filename, smt = _q_find_module(m.__name__, path) m = imp.load_module(p, file, filename, smt) finally : if file is not None : file.close() new_path = m.__path__ if type(new_path) == types.ListType : new_path = filename if new_path not in path : path.insert(1, new_path) elif smt[-1] != imp.PY_COMPILED: if p is not packages[-1] : if file is not None : file.close() raise ImportError, "No module named %s" % packages[-1] return file, filename, smt # in case we have been given a package to check return file, filename, smtclass Variable : "Class to hold all information about a variable" def __init__(self, name, type): self.name = name self.type = type self.value = None def __str__(self) : return self.name __repr__ = utils.std_reprdef _filterDir(object, ignoreList) : "Return a list of tokens (attributes) in a class, except for ignoreList" tokens = dir(object) for token in ignoreList : if token in tokens : tokens.remove(token) return tokensdef _getClassTokens(c) : return _filterDir(c, _DEFAULT_CLASS_TOKENS)class Class : "Class to hold all information about a class" def __init__(self, name, module) : self.name = name self.classObject = getattr(module, name) modname = getattr(self.classObject, '__module__', None) if modname is None: # hm, some ExtensionClasses don't have a __module__ attribute # so try parsing the type output typerepr = repr(type(self.classObject)) mo = re.match("^<type ['\"](.+)['\"]>$", typerepr) if mo: modname = ".".join(mo.group(1).split(".")[:-1]) self.module = sys.modules.get(modname) if not self.module: self.module = module global _output txt = _("warning: couldn't find real module for class %s (module name: %s)\n") % (self.classObject, modname) _output.AddLines(txt) self.ignoreAttrs = 0 self.methods = {} self.members = { '__class__': types.ClassType, '__doc__': types.StringType, '__dict__': types.DictType, } self.memberRefs = {} self.statics = {} self.lineNums = {} def __str__(self) : return self.name __repr__ = utils.std_repr def getFirstLine(self) : "Return first line we can find in THIS class, not any base classes" lineNums = [] classDir = dir(self.classObject) for m in self.methods.values() : if m != None and m.function.func_code.co_name in classDir: lineNums.append(m.function.func_code.co_firstlineno) if lineNums : return min(lineNums) return 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -