#!/bin/env python # Simple-minded Python identifier checker (Ka-Ping Yee, 1 April 1997) import sys, getopt, string, tokenize, os def terse_warn(file, linenum, line, message, start=0, end=0): print '%s:%d: %s' % (file, linenum, message) 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') + dir(__builtins__): special[name] = 1 member = {} for name in [].__methods__ + {}.__methods__ + [].append.__members__ + \ warn.__members__ + warn.func_code.__members__ + \ file.__methods__ + file.__members__ + \ tb.__members__ + tb.tb_frame.__members__ + \ ['__dict__', '__methods__', '__members__']: member[name] = 1 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 = {}, {}, {} modfrom = sawimport = 0 last = parent = '' def count(type, token, (srow, scol), (erow, ecol), line, seen = special.has_key, imported = modules.has_key): global sawimport, modfrom, last, parent, modules if token == 'import': sawimport = 1 elif token in ('\r\n', '\n', ';'): modfrom, sawimport = '', 0 elif token == '.': parent = last 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 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(file.name, srow, line, 'dubious reserved name "%s"' % token, scol, ecol) elif last != 'from': position[token] = (srow, line, scol, ecol) finally: last, parent = token, '' try: tokenize.tokenize(file.readline, count) except tokenize.TokenError, message: warn(file.name, 0, '', message) sys.exit(1) unique = [] for name, (linenum, line, start, end) in position.items(): unique.append(linenum, (start, end, name, line)) unique.sort() for linenum, (start, end, name, line) in unique: warn(file.name, linenum, line, ('"%s" used only once', '"%s" defined but unused')[defined.has_key(name)] % name, start, end)