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 """ |
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 |