home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 14 / hacker14.iso / programacao / pythonwin / python.exe / CHECKAPPEND.PY < prev    next >
Encoding:
Python Source  |  2002-09-11  |  4.7 KB  |  168 lines

  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 "%s: 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("%s: I/O Error: %s" % (`file`, str(msg)))
  82.         return
  83.  
  84.     if verbose > 1:
  85.         print "checking", `file`, "..."
  86.  
  87.     ok = AppendChecker(file, f).run()
  88.     if verbose and ok:
  89.         print "%s: 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("%s: Token Error: %s" % (`self.fname`, str(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 '%s'" % `state`)
  163.  
  164.         self.state = state
  165.  
  166. if __name__ == '__main__':
  167.     main()
  168.