source: vendor/python/2.5/Lib/tabnanny.py@ 3298

Last change on this file since 3298 was 3225, checked in by bird, 19 years ago

Python 2.5

File size: 11.1 KB
RevLine 
[3225]1#! /usr/bin/env python
2
3"""The Tab Nanny despises ambiguous indentation. She knows no mercy.
4
5tabnanny -- Detection of ambiguous indentation
6
7For the time being this module is intended to be called as a script.
8However it is possible to import it into an IDE and use the function
9check() described below.
10
11Warning: The API provided by this module is likely to change in future
12releases; such changes may not be backward compatible.
13"""
14
15# Released to the public domain, by Tim Peters, 15 April 1998.
16
17# XXX Note: this is now a standard library module.
18# XXX The API needs to undergo changes however; the current code is too
19# XXX script-like. This will be addressed later.
20
21__version__ = "6"
22
23import os
24import sys
25import getopt
26import tokenize
27if not hasattr(tokenize, 'NL'):
28 raise ValueError("tokenize.NL doesn't exist -- tokenize module too old")
29
30__all__ = ["check", "NannyNag", "process_tokens"]
31
32verbose = 0
33filename_only = 0
34
35def errprint(*args):
36 sep = ""
37 for arg in args:
38 sys.stderr.write(sep + str(arg))
39 sep = " "
40 sys.stderr.write("\n")
41
42def main():
43 global verbose, filename_only
44 try:
45 opts, args = getopt.getopt(sys.argv[1:], "qv")
46 except getopt.error, msg:
47 errprint(msg)
48 return
49 for o, a in opts:
50 if o == '-q':
51 filename_only = filename_only + 1
52 if o == '-v':
53 verbose = verbose + 1
54 if not args:
55 errprint("Usage:", sys.argv[0], "[-v] file_or_directory ...")
56 return
57 for arg in args:
58 check(arg)
59
60class NannyNag(Exception):
61 """
62 Raised by tokeneater() if detecting an ambiguous indent.
63 Captured and handled in check().
64 """
65 def __init__(self, lineno, msg, line):
66 self.lineno, self.msg, self.line = lineno, msg, line
67 def get_lineno(self):
68 return self.lineno
69 def get_msg(self):
70 return self.msg
71 def get_line(self):
72 return self.line
73
74def check(file):
75 """check(file_or_dir)
76
77 If file_or_dir is a directory and not a symbolic link, then recursively
78 descend the directory tree named by file_or_dir, checking all .py files
79 along the way. If file_or_dir is an ordinary Python source file, it is
80 checked for whitespace related problems. The diagnostic messages are
81 written to standard output using the print statement.
82 """
83
84 if os.path.isdir(file) and not os.path.islink(file):
85 if verbose:
86 print "%r: listing directory" % (file,)
87 names = os.listdir(file)
88 for name in names:
89 fullname = os.path.join(file, name)
90 if (os.path.isdir(fullname) and
91 not os.path.islink(fullname) or
92 os.path.normcase(name[-3:]) == ".py"):
93 check(fullname)
94 return
95
96 try:
97 f = open(file)
98 except IOError, msg:
99 errprint("%r: I/O Error: %s" % (file, msg))
100 return
101
102 if verbose > 1:
103 print "checking %r ..." % file
104
105 try:
106 process_tokens(tokenize.generate_tokens(f.readline))
107
108 except tokenize.TokenError, msg:
109 errprint("%r: Token Error: %s" % (file, msg))
110 return
111
112 except IndentationError, msg:
113 errprint("%r: Indentation Error: %s" % (file, msg))
114 return
115
116 except NannyNag, nag:
117 badline = nag.get_lineno()
118 line = nag.get_line()
119 if verbose:
120 print "%r: *** Line %d: trouble in tab city! ***" % (file, badline)
121 print "offending line: %r" % (line,)
122 print nag.get_msg()
123 else:
124 if ' ' in file: file = '"' + file + '"'
125 if filename_only: print file
126 else: print file, badline, repr(line)
127 return
128
129 if verbose:
130 print "%r: Clean bill of health." % (file,)
131
132class Whitespace:
133 # the characters used for space and tab
134 S, T = ' \t'
135
136 # members:
137 # raw
138 # the original string
139 # n
140 # the number of leading whitespace characters in raw
141 # nt
142 # the number of tabs in raw[:n]
143 # norm
144 # the normal form as a pair (count, trailing), where:
145 # count
146 # a tuple such that raw[:n] contains count[i]
147 # instances of S * i + T
148 # trailing
149 # the number of trailing spaces in raw[:n]
150 # It's A Theorem that m.indent_level(t) ==
151 # n.indent_level(t) for all t >= 1 iff m.norm == n.norm.
152 # is_simple
153 # true iff raw[:n] is of the form (T*)(S*)
154
155 def __init__(self, ws):
156 self.raw = ws
157 S, T = Whitespace.S, Whitespace.T
158 count = []
159 b = n = nt = 0
160 for ch in self.raw:
161 if ch == S:
162 n = n + 1
163 b = b + 1
164 elif ch == T:
165 n = n + 1
166 nt = nt + 1
167 if b >= len(count):
168 count = count + [0] * (b - len(count) + 1)
169 count[b] = count[b] + 1
170 b = 0
171 else:
172 break
173 self.n = n
174 self.nt = nt
175 self.norm = tuple(count), b
176 self.is_simple = len(count) <= 1