#!/bin/env python # Simple-minded Python identifier checker (Ka-Ping Yee, 1 April 1997) import sys, string, tokenize, pprint ##import os, getopt import __builtin__ warnings = [] def terse_warn(file, linenum, line, message, start=0, end=0): print '%s:%d: %s' % (file, linenum, message) def log_warn(file, linenum, line, message, start=0, end=0): warnings.append( (file, linenum, message) ) warn = log_warn opt_i = 0 ignore_subobjs = 1 ##def tty_warn(file, linenum, line, message, start=0, end=0): ## print '%s:%d: %s\n %s' % (file, linenum, message, line), ## ##BOLD, NORMAL = '\x1b[1m', '\x1b[0m' ##def vt100_warn(file, linenum, line, message, start=0, end=0): ## print '%s:%d: %s' % (file, linenum, message) ## print ' ' + line[:start] + BOLD + line[start:end] + NORMAL + line[end:], ## ##vt100_compatible = ('vt100', 'vt102', 'xterm', 'ansi', 'iris-ansi', 'linux') ## ##options, args = getopt.getopt(sys.argv[1:], 'vhi') ##if not args or ('-h', '') in options: ## print "PyLint (1 April 1997) by Ka-Ping Yee" ## print "usage: %s [-v] [-i] filename.py" % sys.argv[0] ## print " -v for verbose mode (display source lines)" ## print " -i to import modules that are imported in the file" ## sys.exit(0) ## ##if args[0] == '-': file = sys.stdin ##else: file = open(args[0]) ##opt_i = ('-i', '') in options ##if ('-v', '') not in options: ## warn = terse_warn ##elif os.environ.has_key('TERM') and os.environ['TERM'] in vt100_compatible: ## warn = vt100_warn ##else: ## warn = tty_warn try: 1/0 except: tb = sys.exc_traceback special = {} for name in string.split('and break class continue def del elif else except ' 'exec finally for from global if import in is lambda not or pass print ' 'raise return try while true false') + dir(__builtin__): special[name] = 1 member = {} for name in [].__methods__ + {}.__methods__ + [].append.__members__ + \ warn.__members__ + warn.func_code.__members__ + \ tb.__members__ + tb.tb_frame.__members__ + \ ['__dict__', '__methods__', '__members__']: member[name] = 1 # file.__methods__ + file.__members__ + \ reserved = {} for name in string.split('abs add and bases builtin builtins call class cmp ' 'coerce copy copyright deepcopy del delattr delitem delslice div divmod ' 'file float getattr getinitargs getitem getslice getstate hash hello hex ' 'init int invert len long lshift main mod mul name neg nonzero oct or pos ' 'pow radd rand rcmp rdiv rdivmod repr rlshift rmod rmul ror rpow rrshift ' 'rshift rsub rxor setattr setitem setslice setstate str sub version xor'): reserved['__'+name+'__'] = 1 position, modules, defined = {}, {}, {} def init_globals(afilename): global warnings, position, modules, defined, modfrom, sawimport, last, parent, filename, bracket_depth warnings[:] = [] position.clear(); modules.clear(); defined.clear() modfrom = sawimport = 0 last = parent = '' filename = afilename bracket_depth = 0 init_globals('') def count(type, token, (srow, scol), (erow, ecol), line, seen = special.has_key, imported = modules.has_key): global sawimport, modfrom, last, parent, modules, bracket_depth if token == 'import': sawimport = 1 elif token in ('\r\n', '\n', ';'): modfrom, sawimport = '', 0 elif token == '.': parent = last elif token == '(': bracket_depth = bracket_depth + 1 elif token == ')': bracket_depth = bracket_depth - 1 else: try: if last == 'from': modfrom = token elif last in ('class', 'def'): defined[token] = 1 elif opt_i and modfrom and token == '*': try: for name in dir(__import__(modfrom)): if name[0] != '_': special[name] = 1 except: pass if type != tokenize.NAME or seen(token): return if opt_i and not modfrom and sawimport and not imported(token): try: modules[token] = {} for name in dir(__import__(token)): modules[token][name] = 1 except: pass if parent and member.has_key(token): pass # RB: # Added the following two cases: # Optionally ignore all sub_obj if not in importing mode # Boa can't use importing mode for fear of interpreter pollution # Ignore all wx* names these are from wxPython and usually imported # with a from wxPython.* import * # Maybe test should rather be directly against the wxPython # namespaces # -- elif parent and parent == 'self': special[token] = 1 elif parent and ignore_subobjs and not opt_i: pass elif len(token) >= 3 and token[:2] == 'wx' and token[2] in string.uppercase: pass elif len(token) >= 5 and token[:4] == 'EVT_': pass # -- elif imported(parent) and modules[parent].has_key(token): pass elif position.has_key(token): del position[token] special[token] = 1 elif token[:2] == '__' == token[-2:]: if not reserved.has_key(token): warn(filename, srow, line, 'dubious reserved name "%s"' % token, scol, ecol) elif last != 'from': position[token] = (srow, line, scol, ecol, bracket_depth) finally: last, parent = token, '' def pylint(afile, filename): ## print 'RESERVED' ## pprint.pprint(reserved) ## print 'SPECIAL' ## pprint.pprint(special) init_globals(filename) try: tokenize.tokenize(afile.readline, count) except tokenize.TokenError, message: warn(filename, 0, '', message) sys.exit(1) unique = [] for name, (linenum, line, start, end, brk_dpth) in position.items(): unique.append( (linenum, (start, end, name, line, brk_dpth)) ) unique.sort() for linenum, (start, end, name, line, brk_dpth) in unique: warn(filename, linenum, line, ('"%s" used only once (%d)', '"%s" defined but unused (%d)')[defined.has_key(name)] % (name, brk_dpth), start, end) if __name__ == '__main__': pylint(open('pylint.py'), 'pylint.py') pprint.pprint(warnings)