| 1 | import types
|
|---|
| 2 |
|
|---|
| 3 | import __builtin__
|
|---|
| 4 | _default_stored = set(__builtin__.__dict__.keys())
|
|---|
| 5 |
|
|---|
| 6 | _default_stored.update("""
|
|---|
| 7 | """.split())
|
|---|
| 8 |
|
|---|
| 9 | _default_stored.add(None) # special value for class definition
|
|---|
| 10 |
|
|---|
| 11 | def _default_printer(line_no, argstr):
|
|---|
| 12 | print "line %d: %s" % (line_no, argstr)
|
|---|
| 13 |
|
|---|
| 14 | def find_name_error(o, stored=_default_stored, printer=_default_printer):
|
|---|
| 15 | """Find possibility of NameError
|
|---|
| 16 |
|
|---|
| 17 | unsupported issue:
|
|---|
| 18 | "from foo import *"
|
|---|
| 19 | LOAD_ATTR(foo.bar)
|
|---|
| 20 | """
|
|---|
| 21 | from co2insts import co2insts
|
|---|
| 22 | from get_co import get_co
|
|---|
| 23 |
|
|---|
| 24 | co = get_co(o)
|
|---|
| 25 | stored = set(stored)
|
|---|
| 26 | stored.update(co.co_varnames)
|
|---|
| 27 |
|
|---|
| 28 | children = set()
|
|---|
| 29 | for ins in co2insts(co):
|
|---|
| 30 | if ins.opname.startswith("LOAD_"):
|
|---|
| 31 | if ins.opname == "LOAD_CONST":
|
|---|
| 32 | const = co.co_consts[ins.arg]
|
|---|
| 33 | if type(const) == types.CodeType:
|
|---|
| 34 | children.add(const)
|
|---|
| 35 | continue
|
|---|
| 36 | if ins.opname == "LOAD_ATTR":
|
|---|
| 37 | continue
|
|---|
| 38 |
|
|---|
| 39 | if ins.argstr not in stored:
|
|---|
| 40 | #print o
|
|---|
| 41 | #from _dis import dis
|
|---|
| 42 | #dis(o)
|
|---|
| 43 | printer(ins.line_no, ins.argstr)
|
|---|
| 44 |
|
|---|
| 45 | if ins.opname.startswith("STORE_"):
|
|---|
| 46 | stored.add(ins.argstr)
|
|---|
| 47 |
|
|---|
| 48 | for c in children:
|
|---|
| 49 | find_name_error(c, stored, printer)
|
|---|
| 50 |
|
|---|
| 51 | def recursive(dirname):
|
|---|
| 52 | import os
|
|---|
| 53 | printed_filenames = []
|
|---|
| 54 | def printer(line_no, argstr):
|
|---|
| 55 | if filename not in printed_filenames:
|
|---|
| 56 | print "***", path
|
|---|
| 57 | printed_filenames.append(filename)
|
|---|
| 58 | print "line %d: %s" % (line_no, argstr)
|
|---|
| 59 |
|
|---|
| 60 |
|
|---|
| 61 | for (dp, dn, fns) in os.walk(dirname):
|
|---|
| 62 | for filename in fns:
|
|---|
| 63 | if filename.endswith(".py"):
|
|---|
| 64 | path = os.path.join(dp, filename)
|
|---|
| 65 | find_name_error(
|
|---|
| 66 | file(path),
|
|---|
| 67 | printer=printer)
|
|---|
| 68 |
|
|---|
| 69 |
|
|---|
| 70 | def watch(targets):
|
|---|
| 71 | import os, time
|
|---|
| 72 | def get_mtime(filename):
|
|---|
| 73 | return os.stat(filename).st_mtime
|
|---|
| 74 |
|
|---|
| 75 | old_mtime = {}
|
|---|
| 76 | while 1:
|
|---|
| 77 | time.sleep(0.3)
|
|---|
| 78 | for filename in targets:
|
|---|
| 79 | mtime = get_mtime(filename)
|
|---|
| 80 | if old_mtime.get(filename) < mtime:
|
|---|
| 81 | print "***", filename, "modified"
|
|---|
| 82 | old_mtime[filename] = mtime
|
|---|
| 83 | find_name_error(file(filename))
|
|---|
| 84 |
|
|---|
| 85 | def main():
|
|---|
| 86 | import sys
|
|---|
| 87 | import optparse
|
|---|
| 88 | parser = optparse.OptionParser()
|
|---|
| 89 | parser.add_option("-r", "--recursive", dest="dirname",
|
|---|
| 90 | help="find *.py under the directory", metavar="DIR")
|
|---|
| 91 | parser.add_option("-w", "--watch",
|
|---|
| 92 | action="store_true", dest="watch", default=False,
|
|---|
| 93 | help="watching target continuously(not implemented yet)")
|
|---|
| 94 |
|
|---|
| 95 | (options, args) = parser.parse_args()
|
|---|
| 96 |
|
|---|
| 97 | if options.watch:
|
|---|
| 98 | import os
|
|---|
| 99 | print "watch mode"
|
|---|
| 100 | if options.dirname:
|
|---|
| 101 | targets = []
|
|---|
| 102 | for (dp, dn, fns) in os.walk(options.dirname):
|
|---|
| 103 | for filename in fns:
|
|---|
| 104 | if filename.endswith(".py"):
|
|---|
| 105 | path = os.path.join(dp, filename)
|
|---|
| 106 | targets.append(path)
|
|---|
| 107 | else:
|
|---|
| 108 | targets = sys.argv[1:]
|
|---|
| 109 |
|
|---|
| 110 | watch(targets)
|
|---|
| 111 |
|
|---|
| 112 | if options.dirname:
|
|---|
| 113 | recursive(options.dirname)
|
|---|
| 114 | else:
|
|---|
| 115 | for filename in sys.argv[1:]:
|
|---|
| 116 | find_name_error(file(filename))
|
|---|
| 117 |
|
|---|
| 118 | if __name__ == "__main__":
|
|---|
| 119 | main()
|
|---|