|
1 | | -#! /home/guido/python/src/sparc/python |
2 | 1 | #! /usr/bin/env python |
3 | 2 |
|
4 | | -"""The Tab Nanny despises ambiguous indentation. She knows no mercy. |
| 3 | +"""The Tab Nanny despises ambiguous indentation. She knows no mercy.""" |
5 | 4 |
|
6 | | -CAUTION: this version requires Guido's "NL" patch to lib/tokenize.py, |
7 | | -posted 30-Mar-98. This version will not run at all with an unpatched |
8 | | -tokenize (it will raise AttributeError while loading), while previous |
9 | | -versions will run incorrectly with the patched tokenize. |
10 | | -""" |
| 5 | +# Released to the public domain, by Tim Peters, 4 April 1998. |
11 | 6 |
|
12 | | -# Released to the public domain, by Tim Peters, 30 March 1998. |
13 | | - |
14 | | -__version__ = "2" |
| 7 | +__version__ = "3" |
15 | 8 |
|
16 | 9 | import os |
17 | 10 | import sys |
18 | 11 | import getopt |
19 | 12 | import tokenize |
20 | 13 |
|
21 | | -try: |
22 | | - tokenize.NL |
23 | | -except AttributeError: |
24 | | - raise AttributeError, "Sorry, I need a version of tokenize.py " \ |
25 | | - "that supports the NL pseudo-token." |
26 | | - |
27 | 14 | verbose = 0 |
28 | 15 |
|
29 | 16 | def main(): |
@@ -235,67 +222,131 @@ def format_witnesses(w): |
235 | 222 | prefix = prefix + "s" |
236 | 223 | return prefix + " " + string.join(firsts, ', ') |
237 | 224 |
|
238 | | -indents = [] |
239 | | -check_equal = 0 |
240 | | - |
241 | | -def reset_globals(): |
242 | | - global indents, check_equal |
243 | | - check_equal = 0 |
244 | | - indents = [Whitespace("")] |
245 | | - |
246 | | -def tokeneater(type, token, start, end, line, |
247 | | - INDENT=tokenize.INDENT, |
248 | | - DEDENT=tokenize.DEDENT, |
249 | | - NEWLINE=tokenize.NEWLINE, |
250 | | - COMMENT=tokenize.COMMENT, |
251 | | - NL=tokenize.NL): |
252 | | - global indents, check_equal |
253 | | - |
254 | | - # test in decreasing order of frequency, although the check_equal |
255 | | - # test *must* be last; INDENT and DEDENT appear equally often |
256 | | - |
257 | | - if type in (COMMENT, NL): |
258 | | - # the indentation of these guys is meaningless |
259 | | - pass |
260 | | - |
261 | | - elif type == NEWLINE: |
262 | | - # a program statement, or ENDMARKER, will eventually follow, |
263 | | - # after some (possibly empty) run of tokens of the form |
264 | | - # (NL | COMMENT)* (INDENT | DEDENT+)? |
265 | | - # If an INDENT appears, setting check_equal is wrong, and will |
266 | | - # be undone when we see the INDENT. |
267 | | - check_equal = 1 |
268 | | - |
269 | | - elif type == INDENT: |
270 | | - check_equal = 0 |
271 | | - thisguy = Whitespace(token) |
272 | | - if not indents[-1].less(thisguy): |
273 | | - witness = indents[-1].not_less_witness(thisguy) |
274 | | - msg = "indent not greater e.g. " + format_witnesses(witness) |
275 | | - raise NannyNag(start[0], msg, line) |
276 | | - indents.append(thisguy) |
277 | | - |
278 | | - elif type == DEDENT: |
279 | | - # there's nothing we need to check here! what's important is |
280 | | - # that when the run of DEDENTs ends, the indentation of the |
281 | | - # program statement (or ENDMARKER) that triggered the run is |
282 | | - # equal to what's left at the top of the indents stack |
283 | | - assert check_equal # else no earlier NEWLINE, or an earlier INDENT |
284 | | - del indents[-1] |
285 | | - |
286 | | - elif check_equal: |
287 | | - # this is the first "real token" following a NEWLINE, so it |
288 | | - # must be the first token of the next program statment, or an |
289 | | - # ENDMARKER; the "line" argument exposes the leading whitespace |
290 | | - # for this statement; in the case of ENDMARKER, line is an empty |
291 | | - # string, so will properly match the empty string with which the |
292 | | - # "indents" stack was seeded |
293 | | - check_equal = 0 |
294 | | - thisguy = Whitespace(line) |
295 | | - if not indents[-1].equal(thisguy): |
296 | | - witness = indents[-1].not_equal_witness(thisguy) |
297 | | - msg = "indent not equal e.g. " + format_witnesses(witness) |
298 | | - raise NannyNag(start[0], msg, line) |
| 225 | +# The collection of globals, the reset_globals() function, and the |
| 226 | +# tokeneater() function, depend on which version of tokenize is |
| 227 | +# in use. |
| 228 | + |
| 229 | +if hasattr(tokenize, 'NL'): |
| 230 | + # take advantage of Guido's patch! |
| 231 | + |
| 232 | + indents = [] |
| 233 | + check_equal = 0 |
| 234 | + |
| 235 | + def reset_globals(): |
| 236 | + global indents, check_equal |
| 237 | + check_equal = 0 |
| 238 | + indents = [Whitespace("")] |
| 239 | + |
| 240 | + def tokeneater(type, token, start, end, line, |
| 241 | + INDENT=tokenize.INDENT, |
| 242 | + DEDENT=tokenize.DEDENT, |
| 243 | + NEWLINE=tokenize.NEWLINE, |
| 244 | + COMMENT=tokenize.COMMENT, |
| 245 | + NL=tokenize.NL): |
| 246 | + global indents, check_equal |
| 247 | + |
| 248 | + # test in decreasing order of frequency, although the check_equal |
| 249 | + # test *must* be last; INDENT and DEDENT appear equally often |
| 250 | + |
| 251 | + if type in (COMMENT, NL): |
| 252 | + # the indentation of these guys is meaningless |
| 253 | + pass |
| 254 | + |
| 255 | + elif type == NEWLINE: |
| 256 | + # a program statement, or ENDMARKER, will eventually follow, |
| 257 | + # after some (possibly empty) run of tokens of the form |
| 258 | + # (NL | COMMENT)* (INDENT | DEDENT+)? |
| 259 | + # If an INDENT appears, setting check_equal is wrong, and will |
| 260 | + # be undone when we see the INDENT. |
| 261 | + check_equal = 1 |
| 262 | + |
| 263 | + elif type == INDENT: |
| 264 | + check_equal = 0 |
| 265 | + thisguy = Whitespace(token) |
| 266 | + if not indents[-1].less(thisguy): |
| 267 | + witness = indents[-1].not_less_witness(thisguy) |
| 268 | + msg = "indent not greater e.g. " + format_witnesses(witness) |
| 269 | + raise NannyNag(start[0], msg, line) |
| 270 | + indents.append(thisguy) |
| 271 | + |
| 272 | + elif type == DEDENT: |
| 273 | + # there's nothing we need to check here! what's important is |
| 274 | + # that when the run of DEDENTs ends, the indentation of the |
| 275 | + # program statement (or ENDMARKER) that triggered the run is |
| 276 | + # equal to what's left at the top of the indents stack |
| 277 | + assert check_equal # else no earlier NEWLINE, or an earlier INDENT |
| 278 | + del indents[-1] |
| 279 | + |
| 280 | + elif check_equal: |
| 281 | + # this is the first "real token" following a NEWLINE, so it |
| 282 | + # must be the first token of the next program statement, or an |
| 283 | + # ENDMARKER; the "line" argument exposes the leading whitespace |
| 284 | + # for this statement; in the case of ENDMARKER, line is an empty |
| 285 | + # string, so will properly match the empty string with which the |
| 286 | + # "indents" stack was seeded |
| 287 | + check_equal = 0 |
| 288 | + thisguy = Whitespace(line) |
| 289 | + if not indents[-1].equal(thisguy): |
| 290 | + witness = indents[-1].not_equal_witness(thisguy) |
| 291 | + msg = "indent not equal e.g. " + format_witnesses(witness) |
| 292 | + raise NannyNag(start[0], msg, line) |
| 293 | + |
| 294 | +else: |
| 295 | + # unpatched version of tokenize |
| 296 | + |
| 297 | + nesting_level = 0 |
| 298 | + indents = [] |
| 299 | + check_equal = 0 |
| 300 | + |
| 301 | + def reset_globals(): |
| 302 | + global nesting_level, indents, check_equal |
| 303 | + nesting_level = check_equal = 0 |
| 304 | + indents = [Whitespace("")] |
| 305 | + |
| 306 | + def tokeneater(type, token, start, end, line, |
| 307 | + INDENT=tokenize.INDENT, |
| 308 | + DEDENT=tokenize.DEDENT, |
| 309 | + NEWLINE=tokenize.NEWLINE, |
| 310 | + COMMENT=tokenize.COMMENT, |
| 311 | + OP=tokenize.OP): |
| 312 | + global nesting_level, indents, check_equal |
| 313 | + |
| 314 | + if type == INDENT: |
| 315 | + check_equal = 0 |
| 316 | + thisguy = Whitespace(token) |
| 317 | + if not indents[-1].less(thisguy): |
| 318 | + witness = indents[-1].not_less_witness(thisguy) |
| 319 | + msg = "indent not greater e.g. " + format_witnesses(witness) |
| 320 | + raise NannyNag(start[0], msg, line) |
| 321 | + indents.append(thisguy) |
| 322 | + |
| 323 | + elif type == DEDENT: |
| 324 | + del indents[-1] |
| 325 | + |
| 326 | + elif type == NEWLINE: |
| 327 | + if nesting_level == 0: |
| 328 | + check_equal = 1 |
| 329 | + |
| 330 | + elif type == COMMENT: |
| 331 | + pass |
| 332 | + |
| 333 | + elif check_equal: |
| 334 | + check_equal = 0 |
| 335 | + thisguy = Whitespace(line) |
| 336 | + if not indents[-1].equal(thisguy): |
| 337 | + witness = indents[-1].not_equal_witness(thisguy) |
| 338 | + msg = "indent not equal e.g. " + format_witnesses(witness) |
| 339 | + raise NannyNag(start[0], msg, line) |
| 340 | + |
| 341 | + if type == OP and token in ('{', '[', '('): |
| 342 | + nesting_level = nesting_level + 1 |
| 343 | + |
| 344 | + elif type == OP and token in ('}', ']', ')'): |
| 345 | + if nesting_level == 0: |
| 346 | + raise NannyNag(start[0], |
| 347 | + "unbalanced bracket '" + token + "'", |
| 348 | + line) |
| 349 | + nesting_level = nesting_level - 1 |
299 | 350 |
|
300 | 351 | if __name__ == '__main__': |
301 | 352 | main() |
|
0 commit comments