Update to 2.7.3
[profile/ivi/python.git] / Tools / scripts / checkappend.py
1 #! /usr/bin/env python
2
3 # Released to the public domain, by Tim Peters, 28 February 2000.
4
5 """checkappend.py -- search for multi-argument .append() calls.
6
7 Usage:  specify one or more file or directory paths:
8     checkappend [-v] file_or_dir [file_or_dir] ...
9
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.
13
14 Use -v for status msgs.  Use -vv for more status msgs.
15
16 In the absence of -v, the only output is pairs of the form
17
18     filename(linenumber):
19     line containing the suspicious append
20
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
24 will be listed.
25
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:
28
29     somelist = []
30     push = somelist.append
31     push(1, 2, 3)
32 """
33
34 __version__ = 1, 0, 0
35
36 import os
37 import sys
38 import getopt
39 import tokenize
40
41 verbose = 0
42
43 def errprint(*args):
44     msg = ' '.join(args)
45     sys.stderr.write(msg)
46     sys.stderr.write("\n")
47
48 def main():
49     args = sys.argv[1:]
50     global verbose
51     try:
52         opts, args = getopt.getopt(sys.argv[1:], "v")
53     except getopt.error, msg:
54         errprint(str(msg) + "\n\n" + __doc__)
55         return
56     for opt, optarg in opts:
57         if opt == '-v':
58             verbose = verbose + 1
59     if not args:
60         errprint(__doc__)
61         return
62     for arg in args:
63         check(arg)
64
65 def check(file):
66     if os.path.isdir(file) and not os.path.islink(file):
67         if verbose:
68             print "%r: listing directory" % (file,)
69         names = os.listdir(file)
70         for name in names:
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"):
75                 check(fullname)
76         return
77
78     try:
79         f = open(file)
80     except IOError, msg:
81         errprint("%r: I/O Error: %s" % (file, msg))
82         return
83
84     if verbose > 1:
85         print "checking %r ..." % (file,)
86
87     ok = AppendChecker(file, f).run()
88     if verbose and ok:
89         print "%r: Clean bill of health." % (file,)
90
91 [FIND_DOT,
92  FIND_APPEND,
93  FIND_LPAREN,
94  FIND_COMMA,
95  FIND_STMT]   = range(5)
96
97 class AppendChecker:
98     def __init__(self, fname, file):
99         self.fname = fname
100         self.file = file
101         self.state = FIND_DOT
102         self.nerrors = 0
103
104     def run(self):
105         try:
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
111
112     def tokeneater(self, type, token, start, end, line,
113                 NEWLINE=tokenize.NEWLINE,
114                 JUNK=(tokenize.COMMENT, tokenize.NL),
115                 OP=tokenize.OP,
116                 NAME=tokenize.NAME):
117
118         state = self.state
119
120         if type in JUNK:
121             pass
122
123         elif state is FIND_DOT:
124             if type is OP and token == ".":
125                 state = FIND_APPEND
126
127         elif state is FIND_APPEND:
128             if type is NAME and token == "append":
129                 self.line = line
130                 self.lineno = start[0]
131                 state = FIND_LPAREN
132             else:
133                 state = FIND_DOT
134
135         elif state is FIND_LPAREN:
136             if type is OP and token == "(":
137                 self.level = 1
138                 state = FIND_COMMA
139             else:
140                 state = FIND_DOT
141
142         elif state is FIND_COMMA:
143             if type is OP:
144                 if token in ("(", "{", "["):
145                     self.level = self.level + 1
146                 elif token in (")", "}", "]"):
147                     self.level = self.level - 1
148                     if self.level == 0:
149                         state = FIND_DOT
150                 elif token == "," and self.level == 1:
151                     self.nerrors = self.nerrors + 1
152                     print "%s(%d):\n%s" % (self.fname, self.lineno,
153                                            self.line)
154                     # don't gripe about this stmt again
155                     state = FIND_STMT
156
157         elif state is FIND_STMT:
158             if type is NEWLINE:
159                 state = FIND_DOT
160
161         else:
162             raise SystemError("unknown internal state '%r'" % (state,))
163
164         self.state = state
165
166 if __name__ == '__main__':
167     main()