46 if not hasattr(tokenize, 'NL'): |
46 if not hasattr(tokenize, 'NL'): |
47 raise ValueError("tokenize.NL doesn't exist -- tokenize module too old") |
47 raise ValueError("tokenize.NL doesn't exist -- tokenize module too old") |
48 |
48 |
49 __all__ = ["check", "NannyNag", "process_tokens"] |
49 __all__ = ["check", "NannyNag", "process_tokens"] |
50 |
50 |
|
51 |
51 class NannyNag(Exception): |
52 class NannyNag(Exception): |
52 """ |
53 """ |
53 Raised by tokeneater() if detecting an ambiguous indent. |
54 Raised by tokeneater() if detecting an ambiguous indent. |
54 Captured and handled in check(). |
55 Captured and handled in check(). |
55 """ |
56 """ |
84 Method to retrieve the offending line. |
85 Method to retrieve the offending line. |
85 |
86 |
86 @return The line of code (string) |
87 @return The line of code (string) |
87 """ |
88 """ |
88 return self.line |
89 return self.line |
|
90 |
89 |
91 |
90 def check(filename, codestring): |
92 def check(filename, codestring): |
91 """ |
93 """ |
92 Private function to check one Python source file for whitespace related problems. |
94 Private function to check one Python source file for whitespace related problems. |
93 |
95 |
119 |
121 |
120 except Exception, err: |
122 except Exception, err: |
121 return (True, filename, "1", "Unspecific Error: %s" % unicode(err)) |
123 return (True, filename, "1", "Unspecific Error: %s" % unicode(err)) |
122 |
124 |
123 return (False, None, None, None) |
125 return (False, None, None, None) |
|
126 |
124 |
127 |
125 class Whitespace(object): |
128 class Whitespace(object): |
126 """ |
129 """ |
127 Class implementing the whitespace checker. |
130 Class implementing the whitespace checker. |
128 """ |
131 """ |
169 count = count + [0] * (b - len(count) + 1) |
172 count = count + [0] * (b - len(count) + 1) |
170 count[b] = count[b] + 1 |
173 count[b] = count[b] + 1 |
171 b = 0 |
174 b = 0 |
172 else: |
175 else: |
173 break |
176 break |
174 self.n = n |
177 self.n = n |
175 self.nt = nt |
178 self.nt = nt |
176 self.norm = tuple(count), b |
179 self.norm = tuple(count), b |
177 self.is_simple = len(count) <= 1 |
180 self.is_simple = len(count) <= 1 |
178 |
181 |
179 # return length of longest contiguous run of spaces (whether or not |
182 # return length of longest contiguous run of spaces (whether or not |
180 # preceding a tab) |
183 # preceding a tab) |
184 |
187 |
185 @return The length of longest contiguous run of spaces (whether or not |
188 @return The length of longest contiguous run of spaces (whether or not |
186 preceding a tab) |
189 preceding a tab) |
187 """ |
190 """ |
188 count, trailing = self.norm |
191 count, trailing = self.norm |
189 return max(len(count)-1, trailing) |
192 return max(len(count) - 1, trailing) |
190 |
193 |
191 def indent_level(self, tabsize): |
194 def indent_level(self, tabsize): |
192 """ |
195 """ |
193 Method to determine the indentation level. |
196 Method to determine the indentation level. |
194 |
197 |
210 # and note that i/ts*count[i] is 0 when i < ts |
213 # and note that i/ts*count[i] is 0 when i < ts |
211 |
214 |
212 count, trailing = self.norm |
215 count, trailing = self.norm |
213 il = 0 |
216 il = 0 |
214 for i in range(tabsize, len(count)): |
217 for i in range(tabsize, len(count)): |
215 il = il + i/tabsize * count[i] |
218 il = il + i / tabsize * count[i] |
216 return trailing + tabsize * (il + self.nt) |
219 return trailing + tabsize * (il + self.nt) |
217 |
220 |
218 # return true iff self.indent_level(t) == other.indent_level(t) |
221 # return true iff self.indent_level(t) == other.indent_level(t) |
219 # for all t >= 1 |
222 # for all t >= 1 |
220 def equal(self, other): |
223 def equal(self, other): |
242 i1 == self.indent_level(ts) != other.indent_level(ts) == i2. |
245 i1 == self.indent_level(ts) != other.indent_level(ts) == i2. |
243 """ |
246 """ |
244 n = max(self.longest_run_of_spaces(), |
247 n = max(self.longest_run_of_spaces(), |
245 other.longest_run_of_spaces()) + 1 |
248 other.longest_run_of_spaces()) + 1 |
246 a = [] |
249 a = [] |
247 for ts in range(1, n+1): |
250 for ts in range(1, n + 1): |
248 if self.indent_level(ts) != other.indent_level(ts): |
251 if self.indent_level(ts) != other.indent_level(ts): |
249 a.append( (ts, |
252 a.append((ts, |
250 self.indent_level(ts), |
253 self.indent_level(ts), |
251 other.indent_level(ts)) ) |
254 other.indent_level(ts))) |
252 return a |
255 return a |
253 |
256 |
254 # Return True iff self.indent_level(t) < other.indent_level(t) |
257 # Return True iff self.indent_level(t) < other.indent_level(t) |
255 # for all t >= 1. |
258 # for all t >= 1. |
256 # The algorithm is due to Vincent Broman. |
259 # The algorithm is due to Vincent Broman. |
264 # M.num_tabs() <= N.num_tabs(). Proof is easy but kinda long-winded. |
267 # M.num_tabs() <= N.num_tabs(). Proof is easy but kinda long-winded. |
265 # XXXwrite that up. |
268 # XXXwrite that up. |
266 # Note that M is of the form (T*)(S*) iff len(M.norm[0]) <= 1. |
269 # Note that M is of the form (T*)(S*) iff len(M.norm[0]) <= 1. |
267 def less(self, other): |
270 def less(self, other): |
268 """ |
271 """ |
269 Method to compare the indentation level against another Whitespace objects to |
272 Method to compare the indentation level against another Whitespace objects to |
270 be smaller. |
273 be smaller. |
271 |
274 |
272 @param other Whitespace object to compare against. |
275 @param other Whitespace object to compare against. |
273 @return True, if we compare less against the other Whitespace object. |
276 @return True, if we compare less against the other Whitespace object. |
274 """ |
277 """ |
277 if self.is_simple and other.is_simple: |
280 if self.is_simple and other.is_simple: |
278 return self.nt <= other.nt |
281 return self.nt <= other.nt |
279 n = max(self.longest_run_of_spaces(), |
282 n = max(self.longest_run_of_spaces(), |
280 other.longest_run_of_spaces()) + 1 |
283 other.longest_run_of_spaces()) + 1 |
281 # the self.n >= other.n test already did it for ts=1 |
284 # the self.n >= other.n test already did it for ts=1 |
282 for ts in range(2, n+1): |
285 for ts in range(2, n + 1): |
283 if self.indent_level(ts) >= other.indent_level(ts): |
286 if self.indent_level(ts) >= other.indent_level(ts): |
284 return False |
287 return False |
285 return True |
288 return True |
286 |
289 |
287 # return a list of tuples (ts, i1, i2) such that |
290 # return a list of tuples (ts, i1, i2) such that |
300 i1 == self.indent_level(ts) >= other.indent_level(ts) == i2. |
303 i1 == self.indent_level(ts) >= other.indent_level(ts) == i2. |
301 """ |
304 """ |
302 n = max(self.longest_run_of_spaces(), |
305 n = max(self.longest_run_of_spaces(), |
303 other.longest_run_of_spaces()) + 1 |
306 other.longest_run_of_spaces()) + 1 |
304 a = [] |
307 a = [] |
305 for ts in range(1, n+1): |
308 for ts in range(1, n + 1): |
306 if self.indent_level(ts) >= other.indent_level(ts): |
309 if self.indent_level(ts) >= other.indent_level(ts): |
307 a.append( (ts, |
310 a.append((ts, |
308 self.indent_level(ts), |
311 self.indent_level(ts), |
309 other.indent_level(ts)) ) |
312 other.indent_level(ts))) |
310 return a |
313 return a |
|
314 |
311 |
315 |
312 def format_witnesses(w): |
316 def format_witnesses(w): |
313 """ |
317 """ |
314 Function to format the witnesses as a readable string. |
318 Function to format the witnesses as a readable string. |
315 |
319 |
319 firsts = map(lambda tup: str(tup[0]), w) |
323 firsts = map(lambda tup: str(tup[0]), w) |
320 prefix = "at tab size" |
324 prefix = "at tab size" |
321 if len(w) > 1: |
325 if len(w) > 1: |
322 prefix = prefix + "s" |
326 prefix = prefix + "s" |
323 return prefix + " " + ', '.join(firsts) |
327 return prefix + " " + ', '.join(firsts) |
|
328 |
324 |
329 |
325 def process_tokens(tokens): |
330 def process_tokens(tokens): |
326 """ |
331 """ |
327 Function processing all tokens generated by a tokenizer run. |
332 Function processing all tokens generated by a tokenizer run. |
328 |
333 |