Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: third_party/pylint/checkers/format.py

Issue 753543006: pylint: upgrade to 1.4.0 (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/pylint/checkers/exceptions.py ('k') | third_party/pylint/checkers/imports.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). 1 # Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
2 # 2 #
3 # This program is free software; you can redistribute it and/or modify it under 3 # This program is free software; you can redistribute it and/or modify it under
4 # the terms of the GNU General Public License as published by the Free Software 4 # the terms of the GNU General Public License as published by the Free Software
5 # Foundation; either version 2 of the License, or (at your option) any later 5 # Foundation; either version 2 of the License, or (at your option) any later
6 # version. 6 # version.
7 # 7 #
8 # This program is distributed in the hope that it will be useful, but WITHOUT 8 # This program is distributed in the hope that it will be useful, but WITHOUT
9 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 10 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11 # 11 #
12 # You should have received a copy of the GNU General Public License along with 12 # You should have received a copy of the GNU General Public License along with
13 # this program; if not, write to the Free Software Foundation, Inc., 13 # this program; if not, write to the Free Software Foundation, Inc.,
14 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 14 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 """Python code format's checker. 15 """Python code format's checker.
16 16
17 By default try to follow Guido's style guide : 17 By default try to follow Guido's style guide :
18 18
19 http://www.python.org/doc/essays/styleguide.html 19 http://www.python.org/doc/essays/styleguide.html
20 20
21 Some parts of the process_token method is based from The Tab Nanny std module. 21 Some parts of the process_token method is based from The Tab Nanny std module.
22 """ 22 """
23 23
24 import keyword 24 import keyword
25 import sys 25 import sys
26 import tokenize 26 import tokenize
27 from functools import reduce # pylint: disable=redefined-builtin
27 28
28 if not hasattr(tokenize, 'NL'): 29 import six
29 raise ValueError("tokenize.NL doesn't exist -- tokenize module too old") 30 from six.moves import zip, map, filter # pylint: disable=redefined-builtin
30 31
31 from astroid import nodes 32 from astroid import nodes
32 33
33 from pylint.interfaces import ITokenChecker, IAstroidChecker, IRawChecker 34 from pylint.interfaces import ITokenChecker, IAstroidChecker, IRawChecker
34 from pylint.checkers import BaseTokenChecker 35 from pylint.checkers import BaseTokenChecker
35 from pylint.checkers.utils import check_messages 36 from pylint.checkers.utils import check_messages
36 from pylint.utils import WarningScope, OPTION_RGX 37 from pylint.utils import WarningScope, OPTION_RGX
37 38
38 _CONTINUATION_BLOCK_OPENERS = ['elif', 'except', 'for', 'if', 'while', 'def', 'c lass'] 39 _CONTINUATION_BLOCK_OPENERS = ['elif', 'except', 'for', 'if', 'while', 'def', 'c lass']
39 _KEYWORD_TOKENS = ['assert', 'del', 'elif', 'except', 'for', 'if', 'in', 'not', 40 _KEYWORD_TOKENS = ['assert', 'del', 'elif', 'except', 'for', 'if', 'in', 'not',
(...skipping 18 matching lines...) Expand all
58 59
59 # Whitespace checking config constants 60 # Whitespace checking config constants
60 _DICT_SEPARATOR = 'dict-separator' 61 _DICT_SEPARATOR = 'dict-separator'
61 _TRAILING_COMMA = 'trailing-comma' 62 _TRAILING_COMMA = 'trailing-comma'
62 _NO_SPACE_CHECK_CHOICES = [_TRAILING_COMMA, _DICT_SEPARATOR] 63 _NO_SPACE_CHECK_CHOICES = [_TRAILING_COMMA, _DICT_SEPARATOR]
63 64
64 MSGS = { 65 MSGS = {
65 'C0301': ('Line too long (%s/%s)', 66 'C0301': ('Line too long (%s/%s)',
66 'line-too-long', 67 'line-too-long',
67 'Used when a line is longer than a given number of characters.'), 68 'Used when a line is longer than a given number of characters.'),
68 'C0302': ('Too many lines in module (%s)', # was W0302 69 'C0302': ('Too many lines in module (%s/%s)', # was W0302
69 'too-many-lines', 70 'too-many-lines',
70 'Used when a module has too much lines, reducing its readability.' 71 'Used when a module has too much lines, reducing its readability.'
71 ), 72 ),
72 'C0303': ('Trailing whitespace', 73 'C0303': ('Trailing whitespace',
73 'trailing-whitespace', 74 'trailing-whitespace',
74 'Used when there is whitespace between the end of a line and the ' 75 'Used when there is whitespace between the end of a line and the '
75 'newline.'), 76 'newline.'),
76 'C0304': ('Final newline missing', 77 'C0304': ('Final newline missing',
77 'missing-final-newline', 78 'missing-final-newline',
78 'Used when the last line in a file is missing a newline.'), 79 'Used when the last line in a file is missing a newline.'),
(...skipping 19 matching lines...) Expand all
98 'superfluous-parens', 99 'superfluous-parens',
99 'Used when a single item in parentheses follows an if, for, or ' 100 'Used when a single item in parentheses follows an if, for, or '
100 'other keyword.'), 101 'other keyword.'),
101 'C0326': ('%s space %s %s %s\n%s', 102 'C0326': ('%s space %s %s %s\n%s',
102 'bad-whitespace', 103 'bad-whitespace',
103 ('Used when a wrong number of spaces is used around an operator, ' 104 ('Used when a wrong number of spaces is used around an operator, '
104 'bracket or block opener.'), 105 'bracket or block opener.'),
105 {'old_names': [('C0323', 'no-space-after-operator'), 106 {'old_names': [('C0323', 'no-space-after-operator'),
106 ('C0324', 'no-space-after-comma'), 107 ('C0324', 'no-space-after-comma'),
107 ('C0322', 'no-space-before-operator')]}), 108 ('C0322', 'no-space-before-operator')]}),
108 'W0331': ('Use of the <> operator',
109 'old-ne-operator',
110 'Used when the deprecated "<>" operator is used instead '
111 'of "!=".',
112 {'maxversion': (3, 0)}),
113 'W0332': ('Use of "l" as long integer identifier', 109 'W0332': ('Use of "l" as long integer identifier',
114 'lowercase-l-suffix', 110 'lowercase-l-suffix',
115 'Used when a lower case "l" is used to mark a long integer. You ' 111 'Used when a lower case "l" is used to mark a long integer. You '
116 'should use a upper case "L" since the letter "l" looks too much ' 112 'should use a upper case "L" since the letter "l" looks too much '
117 'like the digit "1"', 113 'like the digit "1"',
118 {'maxversion': (3, 0)}), 114 {'maxversion': (3, 0)}),
119 'W0333': ('Use of the `` operator', 115 'C0327': ('Mixed line endings LF and CRLF',
120 'backtick', 116 'mixed-line-endings',
121 'Used when the deprecated "``" (backtick) operator is used ' 117 'Used when there are mixed (LF and CRLF) newline signs in a file.' ),
122 'instead of the str() function.', 118 'C0328': ('Unexpected line ending format. There is \'%s\' while it should be \'%s\'.',
123 {'scope': WarningScope.NODE, 'maxversion': (3, 0)}), 119 'unexpected-line-ending-format',
120 'Used when there is different newline than expected.'),
124 } 121 }
125 122
126 123
127 def _underline_token(token): 124 def _underline_token(token):
128 length = token[3][1] - token[2][1] 125 length = token[3][1] - token[2][1]
129 offset = token[2][1] 126 offset = token[2][1]
130 return token[4] + (' ' * offset) + ('^' * length) 127 return token[4] + (' ' * offset) + ('^' * length)
131 128
132 129
133 def _column_distance(token1, token2): 130 def _column_distance(token1, token2):
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 position, 326 position,
330 _Offsets(indentation + self._continuation_size, indentation), 327 _Offsets(indentation + self._continuation_size, indentation),
331 _BeforeBlockOffsets(indentation + self._continuation_size, 328 _BeforeBlockOffsets(indentation + self._continuation_size,
332 indentation + self._continuation_size * 2)) 329 indentation + self._continuation_size * 2))
333 elif bracket == ':': 330 elif bracket == ':':
334 # If the dict key was on the same line as the open brace, the new 331 # If the dict key was on the same line as the open brace, the new
335 # correct indent should be relative to the key instead of the 332 # correct indent should be relative to the key instead of the
336 # current indent level 333 # current indent level
337 paren_align = self._cont_stack[-1].valid_outdent_offsets 334 paren_align = self._cont_stack[-1].valid_outdent_offsets
338 next_align = self._cont_stack[-1].valid_continuation_offsets.copy() 335 next_align = self._cont_stack[-1].valid_continuation_offsets.copy()
339 next_align[next_align.keys()[0] + self._continuation_size] = True 336 next_align_keys = list(next_align.keys())
337 next_align[next_align_keys[0] + self._continuation_size] = True
340 # Note that the continuation of 338 # Note that the continuation of
341 # d = { 339 # d = {
342 # 'a': 'b' 340 # 'a': 'b'
343 # 'c' 341 # 'c'
344 # } 342 # }
345 # is handled by the special-casing for hanging continued string inde nts. 343 # is handled by the special-casing for hanging continued string inde nts.
346 return _ContinuedIndent(HANGING_DICT_VALUE, bracket, position, paren _align, next_align) 344 return _ContinuedIndent(HANGING_DICT_VALUE, bracket, position, paren _align, next_align)
347 else: 345 else:
348 return _ContinuedIndent( 346 return _ContinuedIndent(
349 HANGING, 347 HANGING,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 else: 392 else:
395 self._cont_stack.append( 393 self._cont_stack.append(
396 self._continuation_inside_bracket(token, position)) 394 self._continuation_inside_bracket(token, position))
397 395
398 396
399 class FormatChecker(BaseTokenChecker): 397 class FormatChecker(BaseTokenChecker):
400 """checks for : 398 """checks for :
401 * unauthorized constructions 399 * unauthorized constructions
402 * strict indentation 400 * strict indentation
403 * line length 401 * line length
404 * use of <> instead of !=
405 """ 402 """
406 403
407 __implements__ = (ITokenChecker, IAstroidChecker, IRawChecker) 404 __implements__ = (ITokenChecker, IAstroidChecker, IRawChecker)
408 405
409 # configuration section name 406 # configuration section name
410 name = 'format' 407 name = 'format'
411 # messages 408 # messages
412 msgs = MSGS 409 msgs = MSGS
413 # configuration options 410 # configuration options
414 # for available dict keys/values see the optik parser 'add_option' method 411 # for available dict keys/values see the optik parser 'add_option' method
415 options = (('max-line-length', 412 options = (('max-line-length',
416 {'default' : 80, 'type' : "int", 'metavar' : '<int>', 413 {'default' : 100, 'type' : "int", 'metavar' : '<int>',
417 'help' : 'Maximum number of characters on a single line.'}), 414 'help' : 'Maximum number of characters on a single line.'}),
418 ('ignore-long-lines', 415 ('ignore-long-lines',
419 {'type': 'regexp', 'metavar': '<regexp>', 416 {'type': 'regexp', 'metavar': '<regexp>',
420 'default': r'^\s*(# )?<?https?://\S+>?$', 417 'default': r'^\s*(# )?<?https?://\S+>?$',
421 'help': ('Regexp for a line that is allowed to be longer than ' 418 'help': ('Regexp for a line that is allowed to be longer than '
422 'the limit.')}), 419 'the limit.')}),
423 ('single-line-if-stmt', 420 ('single-line-if-stmt',
424 {'default': False, 'type' : 'yn', 'metavar' : '<y_or_n>', 421 {'default': False, 'type' : 'yn', 'metavar' : '<y_or_n>',
425 'help' : ('Allow the body of an if to be on the same ' 422 'help' : ('Allow the body of an if to be on the same '
426 'line as the test if there is no else.')}), 423 'line as the test if there is no else.')}),
427 ('no-space-check', 424 ('no-space-check',
428 {'default': ','.join(_NO_SPACE_CHECK_CHOICES), 425 {'default': ','.join(_NO_SPACE_CHECK_CHOICES),
429 'type': 'multiple_choice', 426 'type': 'multiple_choice',
430 'choices': _NO_SPACE_CHECK_CHOICES, 427 'choices': _NO_SPACE_CHECK_CHOICES,
431 'help': ('List of optional constructs for which whitespace ' 428 'help': ('List of optional constructs for which whitespace '
432 'checking is disabled')}), 429 'checking is disabled')}),
433 ('max-module-lines', 430 ('max-module-lines',
434 {'default' : 1000, 'type' : 'int', 'metavar' : '<int>', 431 {'default' : 1000, 'type' : 'int', 'metavar' : '<int>',
435 'help': 'Maximum number of lines in a module'} 432 'help': 'Maximum number of lines in a module'}
436 ), 433 ),
437 ('indent-string', 434 ('indent-string',
438 {'default' : ' ', 'type' : "string", 'metavar' : '<string>', 435 {'default' : ' ', 'type' : "string", 'metavar' : '<string>',
439 'help' : 'String used as indentation unit. This is usually ' 436 'help' : 'String used as indentation unit. This is usually '
440 '" " (4 spaces) or "\\t" (1 tab).'}), 437 '" " (4 spaces) or "\\t" (1 tab).'}),
441 ('indent-after-paren', 438 ('indent-after-paren',
442 {'type': 'int', 'metavar': '<int>', 'default': 4, 439 {'type': 'int', 'metavar': '<int>', 'default': 4,
443 'help': 'Number of spaces of indent required inside a hanging ' 440 'help': 'Number of spaces of indent required inside a hanging '
444 ' or continued line.'}), 441 ' or continued line.'}),
442 ('expected-line-ending-format',
443 {'type': 'choice', 'metavar': '<empty or LF or CRLF>', 'default' : '',
444 'choices': ['', 'LF', 'CRLF'],
445 'help': 'Expected format of line ending, e.g. empty (any line e nding), LF or CRLF.'}),
445 ) 446 )
446 447
447 def __init__(self, linter=None): 448 def __init__(self, linter=None):
448 BaseTokenChecker.__init__(self, linter) 449 BaseTokenChecker.__init__(self, linter)
449 self._lines = None 450 self._lines = None
450 self._visited_lines = None 451 self._visited_lines = None
451 self._bracket_stack = [None] 452 self._bracket_stack = [None]
452 453
453 def _pop_token(self): 454 def _pop_token(self):
454 self._bracket_stack.pop() 455 self._bracket_stack.pop()
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
489 if self._inside_brackets(':') and tokens[start][1] == 'for': 490 if self._inside_brackets(':') and tokens[start][1] == 'for':
490 self._pop_token() 491 self._pop_token()
491 if tokens[start+1][1] != '(': 492 if tokens[start+1][1] != '(':
492 return 493 return
493 494
494 found_and_or = False 495 found_and_or = False
495 depth = 0 496 depth = 0
496 keyword_token = tokens[start][1] 497 keyword_token = tokens[start][1]
497 line_num = tokens[start][2][0] 498 line_num = tokens[start][2][0]
498 499
499 for i in xrange(start, len(tokens) - 1): 500 for i in range(start, len(tokens) - 1):
500 token = tokens[i] 501 token = tokens[i]
501 502
502 # If we hit a newline, then assume any parens were for continuation. 503 # If we hit a newline, then assume any parens were for continuation.
503 if token[0] == tokenize.NL: 504 if token[0] == tokenize.NL:
504 return 505 return
505 506
506 if token[1] == '(': 507 if token[1] == '(':
507 depth += 1 508 depth += 1
508 elif token[1] == ')': 509 elif token[1] == ')':
509 depth -= 1 510 depth -= 1
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 self._check_space(tokens, i, (_MUST, _MUST)) 616 self._check_space(tokens, i, (_MUST, _MUST))
616 617
617 def _check_space(self, tokens, i, policies): 618 def _check_space(self, tokens, i, policies):
618 def _policy_string(policy): 619 def _policy_string(policy):
619 if policy == _MUST: 620 if policy == _MUST:
620 return 'Exactly one', 'required' 621 return 'Exactly one', 'required'
621 else: 622 else:
622 return 'No', 'allowed' 623 return 'No', 'allowed'
623 624
624 def _name_construct(token): 625 def _name_construct(token):
625 if tokens[i][1] == ',': 626 if token[1] == ',':
626 return 'comma' 627 return 'comma'
627 elif tokens[i][1] == ':': 628 elif token[1] == ':':
628 return ':' 629 return ':'
629 elif tokens[i][1] in '()[]{}': 630 elif token[1] in '()[]{}':
630 return 'bracket' 631 return 'bracket'
631 elif tokens[i][1] in ('<', '>', '<=', '>=', '!=', '=='): 632 elif token[1] in ('<', '>', '<=', '>=', '!=', '=='):
632 return 'comparison' 633 return 'comparison'
633 else: 634 else:
634 if self._inside_brackets('('): 635 if self._inside_brackets('('):
635 return 'keyword argument assignment' 636 return 'keyword argument assignment'
636 else: 637 else:
637 return 'assignment' 638 return 'assignment'
638 639
639 good_space = [True, True] 640 good_space = [True, True]
640 pairs = [(tokens[i-1], tokens[i]), (tokens[i], tokens[i+1])] 641 token = tokens[i]
642 pairs = [(tokens[i-1], token), (token, tokens[i+1])]
641 643
642 for other_idx, (policy, token_pair) in enumerate(zip(policies, pairs)): 644 for other_idx, (policy, token_pair) in enumerate(zip(policies, pairs)):
643 if token_pair[other_idx][0] in _EOL or policy == _IGNORE: 645 if token_pair[other_idx][0] in _EOL or policy == _IGNORE:
644 continue 646 continue
645 647
646 distance = _column_distance(*token_pair) 648 distance = _column_distance(*token_pair)
647 if distance is None: 649 if distance is None:
648 continue 650 continue
649 good_space[other_idx] = ( 651 good_space[other_idx] = (
650 (policy == _MUST and distance == 1) or 652 (policy == _MUST and distance == 1) or
651 (policy == _MUST_NOT and distance == 0)) 653 (policy == _MUST_NOT and distance == 0))
652 654
653 warnings = [] 655 warnings = []
654 if not any(good_space) and policies[0] == policies[1]: 656 if not any(good_space) and policies[0] == policies[1]:
655 warnings.append((policies[0], 'around')) 657 warnings.append((policies[0], 'around'))
656 else: 658 else:
657 for ok, policy, position in zip(good_space, policies, ('before', 'af ter')): 659 for ok, policy, position in zip(good_space, policies, ('before', 'af ter')):
658 if not ok: 660 if not ok:
659 warnings.append((policy, position)) 661 warnings.append((policy, position))
660 for policy, position in warnings: 662 for policy, position in warnings:
661 construct = _name_construct(tokens[i]) 663 construct = _name_construct(token)
662 count, state = _policy_string(policy) 664 count, state = _policy_string(policy)
663 self.add_message('bad-whitespace', line=tokens[i][2][0], 665 self.add_message('bad-whitespace', line=token[2][0],
664 args=(count, state, position, construct, 666 args=(count, state, position, construct,
665 _underline_token(tokens[i]))) 667 _underline_token(token)))
666 668
667 def _inside_brackets(self, left): 669 def _inside_brackets(self, left):
668 return self._bracket_stack[-1] == left 670 return self._bracket_stack[-1] == left
669 671
670 def _handle_old_ne_operator(self, tokens, i):
671 if tokens[i][1] == '<>':
672 self.add_message('old-ne-operator', line=tokens[i][2][0])
673
674 def _prepare_token_dispatcher(self): 672 def _prepare_token_dispatcher(self):
675 raw = [ 673 raw = [
676 (_KEYWORD_TOKENS, 674 (_KEYWORD_TOKENS,
677 self._check_keyword_parentheses), 675 self._check_keyword_parentheses),
678 676
679 (_OPENING_BRACKETS, self._opening_bracket), 677 (_OPENING_BRACKETS, self._opening_bracket),
680 678
681 (_CLOSING_BRACKETS, self._closing_bracket), 679 (_CLOSING_BRACKETS, self._closing_bracket),
682 680
683 (['='], self._check_equals_spacing), 681 (['='], self._check_equals_spacing),
684 682
685 (_SPACED_OPERATORS, self._check_surrounded_by_space), 683 (_SPACED_OPERATORS, self._check_surrounded_by_space),
686 684
687 ([','], self._handle_comma), 685 ([','], self._handle_comma),
688 686
689 ([':'], self._handle_colon), 687 ([':'], self._handle_colon),
690 688
691 (['lambda'], self._open_lambda), 689 (['lambda'], self._open_lambda),
692 690
693 (['<>'], self._handle_old_ne_operator),
694 ] 691 ]
695 692
696 dispatch = {} 693 dispatch = {}
697 for tokens, handler in raw: 694 for tokens, handler in raw:
698 for token in tokens: 695 for token in tokens:
699 dispatch[token] = handler 696 dispatch[token] = handler
700 return dispatch 697 return dispatch
701 698
702 def process_tokens(self, tokens): 699 def process_tokens(self, tokens):
703 """process tokens and search for : 700 """process tokens and search for :
704 701
705 _ non strict indentation (i.e. not always using the <indent> parameter as 702 _ non strict indentation (i.e. not always using the <indent> parameter as
706 indent unit) 703 indent unit)
707 _ too long lines (i.e. longer than <max_chars>) 704 _ too long lines (i.e. longer than <max_chars>)
708 _ optionally bad construct (if given, bad_construct must be a compiled 705 _ optionally bad construct (if given, bad_construct must be a compiled
709 regular expression). 706 regular expression).
710 """ 707 """
711 self._bracket_stack = [None] 708 self._bracket_stack = [None]
712 indents = [0] 709 indents = [0]
713 check_equal = False 710 check_equal = False
714 line_num = 0 711 line_num = 0
715 self._lines = {} 712 self._lines = {}
716 self._visited_lines = {} 713 self._visited_lines = {}
717 token_handlers = self._prepare_token_dispatcher() 714 token_handlers = self._prepare_token_dispatcher()
715 self._last_line_ending = None
718 716
719 self._current_line = ContinuedLineState(tokens, self.config) 717 self._current_line = ContinuedLineState(tokens, self.config)
720 for idx, (tok_type, token, start, _, line) in enumerate(tokens): 718 for idx, (tok_type, token, start, _, line) in enumerate(tokens):
721 if start[0] != line_num: 719 if start[0] != line_num:
722 line_num = start[0] 720 line_num = start[0]
723 # A tokenizer oddity: if an indented line contains a multi-line 721 # A tokenizer oddity: if an indented line contains a multi-line
724 # docstring, the line member of the INDENT token does not contai n 722 # docstring, the line member of the INDENT token does not contai n
725 # the full line; therefore we check the next token on the line. 723 # the full line; therefore we check the next token on the line.
726 if tok_type == tokenize.INDENT: 724 if tok_type == tokenize.INDENT:
727 self.new_line(TokenWrapper(tokens), idx-1, idx+1) 725 self.new_line(TokenWrapper(tokens), idx-1, idx+1)
728 else: 726 else:
729 self.new_line(TokenWrapper(tokens), idx-1, idx) 727 self.new_line(TokenWrapper(tokens), idx-1, idx)
730 728
731 if tok_type == tokenize.NEWLINE: 729 if tok_type == tokenize.NEWLINE:
732 # a program statement, or ENDMARKER, will eventually follow, 730 # a program statement, or ENDMARKER, will eventually follow,
733 # after some (possibly empty) run of tokens of the form 731 # after some (possibly empty) run of tokens of the form
734 # (NL | COMMENT)* (INDENT | DEDENT+)? 732 # (NL | COMMENT)* (INDENT | DEDENT+)?
735 # If an INDENT appears, setting check_equal is wrong, and will 733 # If an INDENT appears, setting check_equal is wrong, and will
736 # be undone when we see the INDENT. 734 # be undone when we see the INDENT.
737 check_equal = True 735 check_equal = True
738 self._process_retained_warnings(TokenWrapper(tokens), idx) 736 self._process_retained_warnings(TokenWrapper(tokens), idx)
739 self._current_line.next_logical_line() 737 self._current_line.next_logical_line()
738 self._check_line_ending(token, line_num)
740 elif tok_type == tokenize.INDENT: 739 elif tok_type == tokenize.INDENT:
741 check_equal = False 740 check_equal = False
742 self.check_indent_level(token, indents[-1]+1, line_num) 741 self.check_indent_level(token, indents[-1]+1, line_num)
743 indents.append(indents[-1]+1) 742 indents.append(indents[-1]+1)
744 elif tok_type == tokenize.DEDENT: 743 elif tok_type == tokenize.DEDENT:
745 # there's nothing we need to check here! what's important is 744 # there's nothing we need to check here! what's important is
746 # that when the run of DEDENTs ends, the indentation of the 745 # that when the run of DEDENTs ends, the indentation of the
747 # program statement (or ENDMARKER) that triggered the run is 746 # program statement (or ENDMARKER) that triggered the run is
748 # equal to what's left at the top of the indents stack 747 # equal to what's left at the top of the indents stack
749 check_equal = True 748 check_equal = True
(...skipping 19 matching lines...) Expand all
769 768
770 try: 769 try:
771 handler = token_handlers[token] 770 handler = token_handlers[token]
772 except KeyError: 771 except KeyError:
773 pass 772 pass
774 else: 773 else:
775 handler(tokens, idx) 774 handler(tokens, idx)
776 775
777 line_num -= 1 # to be ok with "wc -l" 776 line_num -= 1 # to be ok with "wc -l"
778 if line_num > self.config.max_module_lines: 777 if line_num > self.config.max_module_lines:
779 self.add_message('too-many-lines', args=line_num, line=1) 778 # Get the line where the too-many-lines (or its message id)
779 # was disabled or default to 1.
780 symbol = self.linter.msgs_store.check_message_id('too-many-lines')
781 names = (symbol.msgid, 'too-many-lines')
782 line = next(filter(None,
783 map(self.linter._pragma_lineno.get, names)), 1)
784 self.add_message('too-many-lines',
785 args=(line_num, self.config.max_module_lines),
786 line=line)
787
788 def _check_line_ending(self, line_ending, line_num):
789 # check if line endings are mixed
790 if self._last_line_ending is not None:
791 if line_ending != self._last_line_ending:
792 self.add_message('mixed-line-endings', line=line_num)
793
794 self._last_line_ending = line_ending
795
796 # check if line ending is as expected
797 expected = self.config.expected_line_ending_format
798 if expected:
799 line_ending = reduce(lambda x, y: x + y if x != y else x, line_endin g, "") # reduce multiple \n\n\n\n to one \n
800 line_ending = 'LF' if line_ending == '\n' else 'CRLF'
801 if line_ending != expected:
802 self.add_message('unexpected-line-ending-format', args=(line_end ing, expected), line=line_num)
803
780 804
781 def _process_retained_warnings(self, tokens, current_pos): 805 def _process_retained_warnings(self, tokens, current_pos):
782 single_line_block_stmt = not _last_token_on_line_is(tokens, current_pos, ':') 806 single_line_block_stmt = not _last_token_on_line_is(tokens, current_pos, ':')
783 807
784 for indent_pos, state, offsets in self._current_line.retained_warnings: 808 for indent_pos, state, offsets in self._current_line.retained_warnings:
785 block_type = offsets[tokens.start_col(indent_pos)] 809 block_type = offsets[tokens.start_col(indent_pos)]
786 hints = dict((k, v) for k, v in offsets.iteritems() 810 hints = dict((k, v) for k, v in six.iteritems(offsets)
787 if v != block_type) 811 if v != block_type)
788 if single_line_block_stmt and block_type == WITH_BODY: 812 if single_line_block_stmt and block_type == WITH_BODY:
789 self._add_continuation_message(state, hints, tokens, indent_pos) 813 self._add_continuation_message(state, hints, tokens, indent_pos)
790 elif not single_line_block_stmt and block_type == SINGLE_LINE: 814 elif not single_line_block_stmt and block_type == SINGLE_LINE:
791 self._add_continuation_message(state, hints, tokens, indent_pos) 815 self._add_continuation_message(state, hints, tokens, indent_pos)
792 816
793 def _check_continued_indentation(self, tokens, next_idx): 817 def _check_continued_indentation(self, tokens, next_idx):
794 def same_token_around_nl(token_type): 818 def same_token_around_nl(token_type):
795 return (tokens.type(next_idx) == token_type and 819 return (tokens.type(next_idx) == token_type and
796 tokens.type(next_idx-2) == token_type) 820 tokens.type(next_idx-2) == token_type)
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
850 self._check_multi_statement_line(node, line) 874 self._check_multi_statement_line(node, line)
851 return 875 return
852 if line in self._visited_lines: 876 if line in self._visited_lines:
853 return 877 return
854 try: 878 try:
855 tolineno = node.blockstart_tolineno 879 tolineno = node.blockstart_tolineno
856 except AttributeError: 880 except AttributeError:
857 tolineno = node.tolineno 881 tolineno = node.tolineno
858 assert tolineno, node 882 assert tolineno, node
859 lines = [] 883 lines = []
860 for line in xrange(line, tolineno + 1): 884 for line in range(line, tolineno + 1):
861 self._visited_lines[line] = 1 885 self._visited_lines[line] = 1
862 try: 886 try:
863 lines.append(self._lines[line].rstrip()) 887 lines.append(self._lines[line].rstrip())
864 except KeyError: 888 except KeyError:
865 lines.append('') 889 lines.append('')
866 890
867 def _check_multi_statement_line(self, node, line): 891 def _check_multi_statement_line(self, node, line):
868 """Check for lines containing multiple statements.""" 892 """Check for lines containing multiple statements."""
869 # Do not warn about multiple nested context managers 893 # Do not warn about multiple nested context managers
870 # in with statements. 894 # in with statements.
871 if isinstance(node, nodes.With): 895 if isinstance(node, nodes.With):
872 return 896 return
873 # For try... except... finally..., the two nodes 897 # For try... except... finally..., the two nodes
874 # appear to be on the same line due to how the AST is built. 898 # appear to be on the same line due to how the AST is built.
875 if (isinstance(node, nodes.TryExcept) and 899 if (isinstance(node, nodes.TryExcept) and
876 isinstance(node.parent, nodes.TryFinally)): 900 isinstance(node.parent, nodes.TryFinally)):
877 return 901 return
878 if (isinstance(node.parent, nodes.If) and not node.parent.orelse 902 if (isinstance(node.parent, nodes.If) and not node.parent.orelse
879 and self.config.single_line_if_stmt): 903 and self.config.single_line_if_stmt):
880 return 904 return
881 self.add_message('multiple-statements', node=node) 905 self.add_message('multiple-statements', node=node)
882 self._visited_lines[line] = 2 906 self._visited_lines[line] = 2
883 907
884 @check_messages('backtick')
885 def visit_backquote(self, node):
886 self.add_message('backtick', node=node)
887
888 def check_lines(self, lines, i): 908 def check_lines(self, lines, i):
889 """check lines have less than a maximum number of characters 909 """check lines have less than a maximum number of characters
890 """ 910 """
891 max_chars = self.config.max_line_length 911 max_chars = self.config.max_line_length
892 ignore_long_line = self.config.ignore_long_lines 912 ignore_long_line = self.config.ignore_long_lines
893 913
894 for line in lines.splitlines(True): 914 for line in lines.splitlines(True):
895 if not line.endswith('\n'): 915 if not line.endswith('\n'):
896 self.add_message('missing-final-newline', line=i) 916 self.add_message('missing-final-newline', line=i)
897 else: 917 else:
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
935 if indent[0] == '\t': 955 if indent[0] == '\t':
936 i_type = 'tabs' 956 i_type = 'tabs'
937 self.add_message('bad-indentation', line=line_num, 957 self.add_message('bad-indentation', line=line_num,
938 args=(level * unit_size + len(suppl), i_type, 958 args=(level * unit_size + len(suppl), i_type,
939 expected * unit_size)) 959 expected * unit_size))
940 960
941 961
942 def register(linter): 962 def register(linter):
943 """required method to auto register this checker """ 963 """required method to auto register this checker """
944 linter.register_checker(FormatChecker(linter)) 964 linter.register_checker(FormatChecker(linter))
OLDNEW
« no previous file with comments | « third_party/pylint/checkers/exceptions.py ('k') | third_party/pylint/checkers/imports.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698