Plugins/CheckerPlugins/Tabnanny/Tabnanny.py

changeset 945
8cd4d08fa9f6
parent 830
6caa4436dee2
child 1509
c0b5e693b0eb
equal deleted inserted replaced
944:1b59c4ba121e 945:8cd4d08fa9f6
48 if not hasattr(tokenize, 'NL'): 48 if not hasattr(tokenize, 'NL'):
49 raise ValueError("tokenize.NL doesn't exist -- tokenize module too old") 49 raise ValueError("tokenize.NL doesn't exist -- tokenize module too old")
50 50
51 __all__ = ["check", "NannyNag", "process_tokens"] 51 __all__ = ["check", "NannyNag", "process_tokens"]
52 52
53
53 class NannyNag(Exception): 54 class NannyNag(Exception):
54 """ 55 """
55 Raised by tokeneater() if detecting an ambiguous indent. 56 Raised by tokeneater() if detecting an ambiguous indent.
56 Captured and handled in check(). 57 Captured and handled in check().
57 """ 58 """
87 88
88 @return The line of code (string) 89 @return The line of code (string)
89 """ 90 """
90 return self.line 91 return self.line
91 92
92 def check(file, text = ""): 93
94 def check(file, text=""):
93 """ 95 """
94 Private function to check one Python source file for whitespace related problems. 96 Private function to check one Python source file for whitespace related problems.
95 97
96 @param file source filename (string) 98 @param file source filename (string)
97 @param text source text (string) 99 @param text source text (string)
130 132
131 except Exception as err: 133 except Exception as err:
132 return (True, file, "1", "Unspecific Error: {0}".format(str(err))) 134 return (True, file, "1", "Unspecific Error: {0}".format(str(err)))
133 135
134 return (False, None, None, None) 136 return (False, None, None, None)
137
135 138
136 class Whitespace(object): 139 class Whitespace(object):
137 """ 140 """
138 Class implementing the whitespace checker. 141 Class implementing the whitespace checker.
139 """ 142 """
163 """ 166 """
164 Constructor 167 Constructor
165 168
166 @param ws The string to be checked. 169 @param ws The string to be checked.
167 """ 170 """
168 self.raw = ws 171 self.raw = ws
169 S, T = Whitespace.S, Whitespace.T 172 S, T = Whitespace.S, Whitespace.T
170 count = [] 173 count = []
171 b = n = nt = 0 174 b = n = nt = 0
172 for ch in self.raw: 175 for ch in self.raw:
173 if ch == S: 176 if ch == S:
180 count = count + [0] * (b - len(count) + 1) 183 count = count + [0] * (b - len(count) + 1)
181 count[b] = count[b] + 1 184 count[b] = count[b] + 1
182 b = 0 185 b = 0
183 else: 186 else:
184 break 187 break
185 self.n = n 188 self.n = n
186 self.nt = nt 189 self.nt = nt
187 self.norm = tuple(count), b 190 self.norm = tuple(count), b
188 self.is_simple = len(count) <= 1 191 self.is_simple = len(count) <= 1
189 192
190 # return length of longest contiguous run of spaces (whether or not 193 # return length of longest contiguous run of spaces (whether or not
191 # preceding a tab) 194 # preceding a tab)
195 198
196 @return The length of longest contiguous run of spaces (whether or not 199 @return The length of longest contiguous run of spaces (whether or not
197 preceding a tab) 200 preceding a tab)
198 """ 201 """
199 count, trailing = self.norm 202 count, trailing = self.norm
200 return max(len(count)-1, trailing) 203 return max(len(count) - 1, trailing)
201 204
202 def indent_level(self, tabsize): 205 def indent_level(self, tabsize):
203 """ 206 """
204 Method to determine the indentation level. 207 Method to determine the indentation level.
205 208
221 # and note that i/ts*count[i] is 0 when i < ts 224 # and note that i/ts*count[i] is 0 when i < ts
222 225
223 count, trailing = self.norm 226 count, trailing = self.norm
224 il = 0 227 il = 0
225 for i in range(tabsize, len(count)): 228 for i in range(tabsize, len(count)):
226 il = il + i/tabsize * count[i] 229 il = il + i / tabsize * count[i]
227 return trailing + tabsize * (il + self.nt) 230 return trailing + tabsize * (il + self.nt)
228 231
229 # return true iff self.indent_level(t) == other.indent_level(t) 232 # return true iff self.indent_level(t) == other.indent_level(t)
230 # for all t >= 1 233 # for all t >= 1
231 def equal(self, other): 234 def equal(self, other):
253 i1 == self.indent_level(ts) != other.indent_level(ts) == i2. 256 i1 == self.indent_level(ts) != other.indent_level(ts) == i2.
254 """ 257 """
255 n = max(self.longest_run_of_spaces(), 258 n = max(self.longest_run_of_spaces(),
256 other.longest_run_of_spaces()) + 1 259 other.longest_run_of_spaces()) + 1
257 a = [] 260 a = []
258 for ts in range(1, n+1): 261 for ts in range(1, n + 1):
259 if self.indent_level(ts) != other.indent_level(ts): 262 if self.indent_level(ts) != other.indent_level(ts):
260 a.append( (ts, 263 a.append((ts,
261 self.indent_level(ts), 264 self.indent_level(ts),
262 other.indent_level(ts)) ) 265 other.indent_level(ts)))
263 return a 266 return a
264 267
265 # Return True iff self.indent_level(t) < other.indent_level(t) 268 # Return True iff self.indent_level(t) < other.indent_level(t)
266 # for all t >= 1. 269 # for all t >= 1.
267 # The algorithm is due to Vincent Broman. 270 # The algorithm is due to Vincent Broman.
275 # M.num_tabs() <= N.num_tabs(). Proof is easy but kinda long-winded. 278 # M.num_tabs() <= N.num_tabs(). Proof is easy but kinda long-winded.
276 # XXXwrite that up. 279 # XXXwrite that up.
277 # Note that M is of the form (T*)(S*) iff len(M.norm[0]) <= 1. 280 # Note that M is of the form (T*)(S*) iff len(M.norm[0]) <= 1.
278 def less(self, other): 281 def less(self, other):
279 """ 282 """
280 Method to compare the indentation level against another Whitespace objects to 283 Method to compare the indentation level against another Whitespace objects to
281 be smaller. 284 be smaller.
282 285
283 @param other Whitespace object to compare against. 286 @param other Whitespace object to compare against.
284 @return True, if we compare less against the other Whitespace object. 287 @return True, if we compare less against the other Whitespace object.
285 """ 288 """
288 if self.is_simple and other.is_simple: 291 if self.is_simple and other.is_simple:
289 return self.nt <= other.nt 292 return self.nt <= other.nt
290 n = max(self.longest_run_of_spaces(), 293 n = max(self.longest_run_of_spaces(),
291 other.longest_run_of_spaces()) + 1 294 other.longest_run_of_spaces()) + 1
292 # the self.n >= other.n test already did it for ts=1 295 # the self.n >= other.n test already did it for ts=1
293 for ts in range(2, n+1): 296 for ts in range(2, n + 1):
294 if self.indent_level(ts) >= other.indent_level(ts): 297 if self.indent_level(ts) >= other.indent_level(ts):
295 return False 298 return False
296 return True 299 return True
297 300
298 # return a list of tuples (ts, i1, i2) such that 301 # return a list of tuples (ts, i1, i2) such that
311 i1 == self.indent_level(ts) >= other.indent_level(ts) == i2. 314 i1 == self.indent_level(ts) >= other.indent_level(ts) == i2.
312 """ 315 """
313 n = max(self.longest_run_of_spaces(), 316 n = max(self.longest_run_of_spaces(),
314 other.longest_run_of_spaces()) + 1 317 other.longest_run_of_spaces()) + 1
315 a = [] 318 a = []
316 for ts in range(1, n+1): 319 for ts in range(1, n + 1):
317 if self.indent_level(ts) >= other.indent_level(ts): 320 if self.indent_level(ts) >= other.indent_level(ts):
318 a.append( (ts, 321 a.append((ts,
319 self.indent_level(ts), 322 self.indent_level(ts),
320 other.indent_level(ts)) ) 323 other.indent_level(ts)))
321 return a 324 return a
325
322 326
323 def format_witnesses(w): 327 def format_witnesses(w):
324 """ 328 """
325 Function to format the witnesses as a readable string. 329 Function to format the witnesses as a readable string.
326 330
330 firsts = [str(tup[0]) for tup in w] 334 firsts = [str(tup[0]) for tup in w]
331 prefix = "at tab size" 335 prefix = "at tab size"
332 if len(w) > 1: 336 if len(w) > 1:
333 prefix = prefix + "s" 337 prefix = prefix + "s"
334 return prefix + " " + ', '.join(firsts) 338 return prefix + " " + ', '.join(firsts)
339
335 340
336 def process_tokens(tokens): 341 def process_tokens(tokens):
337 """ 342 """
338 Function processing all tokens generated by a tokenizer run. 343 Function processing all tokens generated by a tokenizer run.
339 344

eric ide

mercurial