3 # Released to the public domain, by Tim Peters, 28 February 2000.
5 """checkappend.py -- search for multi-argument .append() calls.
7 Usage: specify one or more file or directory paths:
8 checkappend [-v] file_or_dir [file_or_dir] ...
10 Each file_or_dir is checked for multi-argument .append() calls. When
11 a directory, all .py files in the directory, and recursively in its
12 subdirectories, are checked.
14 Use -v for status msgs. Use -vv for more status msgs.
16 In the absence of -v, the only output is pairs of the form
19 line containing the suspicious append
21 Note that this finds multi-argument append calls regardless of whether
22 they're attached to list objects. If a module defines a class with an
23 append method that takes more than one argument, calls to that method
26 Note that this will not find multi-argument list.append calls made via a
27 bound method object. For example, this is not caught:
30 push = somelist.append
46 sys.stderr.write("\n")
52 opts, args = getopt.getopt(sys.argv[1:], "v")
53 except getopt.error, msg:
54 errprint(str(msg) + "\n\n" + __doc__)
56 for opt, optarg in opts:
66 if os.path.isdir(file) and not os.path.islink(file):
68 print "%r: listing directory" % (file,)
69 names = os.listdir(file)
71 fullname = os.path.join(file, name)
72 if ((os.path.isdir(fullname) and
73 not os.path.islink(fullname))
74 or os.path.normcase(name[-3:]) == ".py"):
81 errprint("%r: I/O Error: %s" % (file, msg))
85 print "checking %r ..." % (file,)
87 ok = AppendChecker(file, f).run()
89 print "%r: Clean bill of health." % (file,)
98 def __init__(self, fname, file):
101 self.state = FIND_DOT
106 tokenize.tokenize(self.file.readline, self.tokeneater)
107 except tokenize.TokenError, msg:
108 errprint("%r: Token Error: %s" % (self.fname, msg))
109 self.nerrors = self.nerrors + 1
110 return self.nerrors == 0
112 def tokeneater(self, type, token, start, end, line,
113 NEWLINE=tokenize.NEWLINE,
114 JUNK=(tokenize.COMMENT, tokenize.NL),
123 elif state is FIND_DOT:
124 if type is OP and token == ".":
127 elif state is FIND_APPEND:
128 if type is NAME and token == "append":
130 self.lineno = start[0]
135 elif state is FIND_LPAREN:
136 if type is OP and token == "(":
142 elif state is FIND_COMMA:
144 if token in ("(", "{", "["):
145 self.level = self.level + 1
146 elif token in (")", "}", "]"):
147 self.level = self.level - 1
150 elif token == "," and self.level == 1:
151 self.nerrors = self.nerrors + 1
152 print "%s(%d):\n%s" % (self.fname, self.lineno,
154 # don't gripe about this stmt again
157 elif state is FIND_STMT:
162 raise SystemError("unknown internal state '%r'" % (state,))
166 if __name__ == '__main__':