diff options
author | Michal Nowikowski <godfryd@gmail.com> | 2014-07-30 05:05:34 +0200 |
---|---|---|
committer | Michal Nowikowski <godfryd@gmail.com> | 2014-07-30 05:05:34 +0200 |
commit | 3b7880ad7abca812b83bc91bd380891538032125 (patch) | |
tree | c00b6f2701aba4f9dfa8961b50d43dad44a4d56e | |
parent | 74230a41d37e2838b027d3a1fbd578e42fad0a0e (diff) | |
parent | a99b0f85c075f43b332901c4a3fac917f7c6e748 (diff) | |
download | pylint-3b7880ad7abca812b83bc91bd380891538032125.tar.gz |
merge
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | checkers/format.py | 31 | ||||
-rw-r--r-- | test/functional/line_endings.py | 4 | ||||
-rw-r--r-- | test/functional/line_endings.rc | 2 | ||||
-rw-r--r-- | test/functional/line_endings.txt | 2 | ||||
-rw-r--r-- | test/input/func_abstract_class_instantiated_py30.py | 66 | ||||
-rw-r--r-- | test/input/func_assigning_non_slot.py | 91 | ||||
-rw-r--r-- | test/input/func_bad_slots.py | 90 | ||||
-rw-r--r-- | test/input/func_trailing_whitespace.py | 2 | ||||
-rw-r--r-- | test/test_func.py | 1 |
10 files changed, 170 insertions, 132 deletions
@@ -2,6 +2,10 @@ ChangeLog for Pylint ==================== -- + * Added new checks for line endings if they are mixed (LF vs CRLF) + or if they are not as expected. New messages: mixed-line-endings, + unexpected-line-ending-format. New option: expected-line-ending-format. + * Fix a false positive with string formatting checker, when encountering a string which uses only position-based arguments. Closes issue #285. @@ -22,14 +26,14 @@ ChangeLog for Pylint Closes issue #233. * Return new astroid class nodes when the inferencer can detect that - that result of a function invocation on a type (like `type` or + that result of a function invocation on a type (like `type` or `abc.ABCMeta`) is requested. Closes #205. * Emit 'undefined-variable' for undefined names when using the Python 3 `metaclass=` argument. * Checkers respect priority now. Close issue #229. - + * Fix a false positive regarding W0511. Closes issue #149. * Fix unused-import false positive with Python 3 metaclasses (#143). @@ -70,7 +74,7 @@ ChangeLog for Pylint * Don't emit 'unused-variable' when assigning to a nonlocal. Closes issue #275. - + * Do not let ImportError propagate from the import checker, leading to crash in some namespace package related cases. Closes issue #203. @@ -1521,6 +1525,3 @@ ChangeLog for Pylint 2003-05-19 -- 0.1 * initial release - - - diff --git a/checkers/format.py b/checkers/format.py index cb31256..34da653 100644 --- a/checkers/format.py +++ b/checkers/format.py @@ -121,6 +121,12 @@ MSGS = { 'Used when the deprecated "``" (backtick) operator is used ' 'instead of the str() function.', {'scope': WarningScope.NODE, 'maxversion': (3, 0)}), + 'C0327': ('Mixed line endings LF and CRLF', + 'mixed-line-endings', + 'Used when there are mixed (LF and CRLF) newline signs in a file.'), + 'C0328': ('Unexpected line ending format. There is \'%s\' while it should be \'%s\'.', + 'unexpected-line-ending-format', + 'Used when there is different newline than expected.'), } @@ -442,7 +448,11 @@ class FormatChecker(BaseTokenChecker): {'type': 'int', 'metavar': '<int>', 'default': 4, 'help': 'Number of spaces of indent required inside a hanging ' ' or continued line.'}), - ) + ('expected-line-ending-format', + {'type': 'choice', 'metavar': '<empty or LF or CRLF>', 'default': '', + 'choices': ['', 'LF', 'CRLF'], + 'help': 'Expected format of line ending, e.g. empty (any line ending), LF or CRLF.'}), + ) def __init__(self, linter=None): BaseTokenChecker.__init__(self, linter) @@ -715,6 +725,7 @@ class FormatChecker(BaseTokenChecker): self._lines = {} self._visited_lines = {} token_handlers = self._prepare_token_dispatcher() + self._last_line_ending = None self._current_line = ContinuedLineState(tokens, self.config) for idx, (tok_type, token, start, _, line) in enumerate(tokens): @@ -737,6 +748,7 @@ class FormatChecker(BaseTokenChecker): check_equal = True self._process_retained_warnings(TokenWrapper(tokens), idx) self._current_line.next_logical_line() + self._check_line_ending(token, line_num) elif tok_type == tokenize.INDENT: check_equal = False self.check_indent_level(token, indents[-1]+1, line_num) @@ -778,6 +790,23 @@ class FormatChecker(BaseTokenChecker): if line_num > self.config.max_module_lines: self.add_message('too-many-lines', args=line_num, line=1) + def _check_line_ending(self, line_ending, line_num): + # check if line endings are mixed + if self._last_line_ending is not None: + if line_ending != self._last_line_ending: + self.add_message('mixed-line-endings', line=line_num) + + self._last_line_ending = line_ending + + # check if line ending is as expected + expected = self.config.expected_line_ending_format + if expected: + line_ending = reduce(lambda x, y: x + y if x != y else x, line_ending, "") # reduce multiple \n\n\n\n to one \n + line_ending = 'LF' if line_ending == '\n' else 'CRLF' + if line_ending != expected: + self.add_message('unexpected-line-ending-format', args=(line_ending, expected), line=line_num) + + def _process_retained_warnings(self, tokens, current_pos): single_line_block_stmt = not _last_token_on_line_is(tokens, current_pos, ':') diff --git a/test/functional/line_endings.py b/test/functional/line_endings.py new file mode 100644 index 0000000..d6bc3fc --- /dev/null +++ b/test/functional/line_endings.py @@ -0,0 +1,4 @@ +"mixing line endings are not welcome" +# +1: [unexpected-line-ending-format, mixed-line-endings] +CONST = 1
+ diff --git a/test/functional/line_endings.rc b/test/functional/line_endings.rc new file mode 100644 index 0000000..95532ea --- /dev/null +++ b/test/functional/line_endings.rc @@ -0,0 +1,2 @@ +[Format] +expected-line-ending-format=LF diff --git a/test/functional/line_endings.txt b/test/functional/line_endings.txt new file mode 100644 index 0000000..a18a872 --- /dev/null +++ b/test/functional/line_endings.txt @@ -0,0 +1,2 @@ +mixed-line-endings:3::Mixed line endings LF and CRLF +unexpected-line-ending-format:3::Unexpected line ending format. There is 'CRLF' while it should be 'LF'. diff --git a/test/input/func_abstract_class_instantiated_py30.py b/test/input/func_abstract_class_instantiated_py30.py index 4bcfd3f..7e7c5ab 100644 --- a/test/input/func_abstract_class_instantiated_py30.py +++ b/test/input/func_abstract_class_instantiated_py30.py @@ -8,36 +8,36 @@ abstract methods. __revision__ = 0 import abc -
-class GoodClass(object, metaclass=abc.ABCMeta):
- pass
-
-class SecondGoodClass(object, metaclass=abc.ABCMeta):
- def test(self):
- """ do nothing. """
- pass
-
-class ThirdGoodClass(object, metaclass=abc.ABCMeta):
- """ This should not raise the warning. """
- def test(self):
- raise NotImplementedError()
-
-class BadClass(object, metaclass=abc.ABCMeta):
- @abc.abstractmethod
- def test(self):
- """ do nothing. """
- pass
-
-class SecondBadClass(object, metaclass=abc.ABCMeta):
- @property
- @abc.abstractmethod
- def test(self):
- """ do nothing. """
-
-def main():
- """ do nothing """
- GoodClass()
- SecondGoodClass()
- ThirdGoodClass()
- BadClass()
- SecondBadClass()
+ +class GoodClass(object, metaclass=abc.ABCMeta): + pass + +class SecondGoodClass(object, metaclass=abc.ABCMeta): + def test(self): + """ do nothing. """ + pass + +class ThirdGoodClass(object, metaclass=abc.ABCMeta): + """ This should not raise the warning. """ + def test(self): + raise NotImplementedError() + +class BadClass(object, metaclass=abc.ABCMeta): + @abc.abstractmethod + def test(self): + """ do nothing. """ + pass + +class SecondBadClass(object, metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def test(self): + """ do nothing. """ + +def main(): + """ do nothing """ + GoodClass() + SecondGoodClass() + ThirdGoodClass() + BadClass() + SecondBadClass() diff --git a/test/input/func_assigning_non_slot.py b/test/input/func_assigning_non_slot.py index 9c91dd2..719637d 100644 --- a/test/input/func_assigning_non_slot.py +++ b/test/input/func_assigning_non_slot.py @@ -8,49 +8,48 @@ __revision__ = 0 class Empty(object): """ empty """ -
-class Bad(object):
- """ missing not in slots. """
-
- __slots__ = ['member']
-
- def __init__(self):
- self.missing = 42
-
-class Bad2(object):
- """ missing not in slots """
- __slots__ = [deque.__name__, 'member']
-
- def __init__(self):
- self.deque = 42
- self.missing = 42
-
-class Bad3(Bad):
- """ missing not found in slots """
-
- __slots__ = ['component']
-
- def __init__(self):
- self.component = 42
- self.member = 24
- self.missing = 42
- super(Bad3, self).__init__()
-
-class Good(Empty):
- """ missing not in slots, but Empty doesn't
- specify __slots__.
- """
- __slots__ = ['a']
-
- def __init__(self):
- self.missing = 42
-
-class Good2(object):
- """ Using __dict__ in slots will be safe. """
-
- __slots__ = ['__dict__', 'comp']
-
- def __init__(self):
- self.comp = 4
- self.missing = 5
-
\ No newline at end of file + +class Bad(object): + """ missing not in slots. """ + + __slots__ = ['member'] + + def __init__(self): + self.missing = 42 + +class Bad2(object): + """ missing not in slots """ + __slots__ = [deque.__name__, 'member'] + + def __init__(self): + self.deque = 42 + self.missing = 42 + +class Bad3(Bad): + """ missing not found in slots """ + + __slots__ = ['component'] + + def __init__(self): + self.component = 42 + self.member = 24 + self.missing = 42 + super(Bad3, self).__init__() + +class Good(Empty): + """ missing not in slots, but Empty doesn't + specify __slots__. + """ + __slots__ = ['a'] + + def __init__(self): + self.missing = 42 + +class Good2(object): + """ Using __dict__ in slots will be safe. """ + + __slots__ = ['__dict__', 'comp'] + + def __init__(self): + self.comp = 4 + self.missing = 5 diff --git a/test/input/func_bad_slots.py b/test/input/func_bad_slots.py index bfb83d7..fbb2080 100644 --- a/test/input/func_bad_slots.py +++ b/test/input/func_bad_slots.py @@ -15,48 +15,48 @@ __revision__ = 0 class NotIterable(object): def __iter_(self): """ do nothing """ -
-class Good(object):
- __slots__ = ()
-
-class SecondGood(object):
- __slots__ = []
-
-class ThirdGood(object):
- __slots__ = ['a']
-
-class FourthGood(object):
- __slots__ = ('a%s' % i for i in range(10))
-
-class FifthGood(object):
- __slots__ = "a"
-
-class SixthGood(object):
- __slots__ = deque(["a", "b", "c"])
-
-class SeventhGood(object):
- __slots__ = {"a": "b", "c": "d"}
-
-class Bad(object):
- __slots__ = list
-
-class SecondBad(object):
- __slots__ = 1
-
-class ThirdBad(object):
- __slots__ = ('a', 2)
-
-class FourthBad(object):
- __slots__ = NotIterable()
-
-class FifthBad(object):
- __slots__ = ("a", "b", "")
-
-class PotentiallyGood(object):
- __slots__ = func()
-
-class PotentiallySecondGood(object):
- __slots__ = ('a', deque.__name__)
-
-class PotentiallyThirdGood(object):
- __slots__ = deque.__name__
+ +class Good(object): + __slots__ = () + +class SecondGood(object): + __slots__ = [] + +class ThirdGood(object): + __slots__ = ['a'] + +class FourthGood(object): + __slots__ = ('a%s' % i for i in range(10)) + +class FifthGood(object): + __slots__ = "a" + +class SixthGood(object): + __slots__ = deque(["a", "b", "c"]) + +class SeventhGood(object): + __slots__ = {"a": "b", "c": "d"} + +class Bad(object): + __slots__ = list + +class SecondBad(object): + __slots__ = 1 + +class ThirdBad(object): + __slots__ = ('a', 2) + +class FourthBad(object): + __slots__ = NotIterable() + +class FifthBad(object): + __slots__ = ("a", "b", "") + +class PotentiallyGood(object): + __slots__ = func() + +class PotentiallySecondGood(object): + __slots__ = ('a', deque.__name__) + +class PotentiallyThirdGood(object): + __slots__ = deque.__name__ diff --git a/test/input/func_trailing_whitespace.py b/test/input/func_trailing_whitespace.py index 2d2786d..aca4a2f 100644 --- a/test/input/func_trailing_whitespace.py +++ b/test/input/func_trailing_whitespace.py @@ -1,5 +1,5 @@ """Regression test for trailing-whitespace (C0303).""" - +# pylint: disable=mixed-line-endings __revision__ = 0 print 'some trailing whitespace' diff --git a/test/test_func.py b/test/test_func.py index 0c09b5e..f11eeaa 100644 --- a/test/test_func.py +++ b/test/test_func.py @@ -47,6 +47,7 @@ class TestTests(testlib.TestCase): PORTED = set(['I0001', 'I0010', 'W0712', 'E1001', 'W1402', 'E1310', 'E0202', 'W0711', 'W0108', 'E0603', 'W0710', 'E0710', 'E0711', 'W1001', 'E1124', 'E1120', 'E1121', 'E1123', 'E1003', 'E1002', 'W0212', + 'C0327', 'C0328', 'W0109', 'E1004', 'W0604', 'W0601', 'W0602', 'C0112', 'C0330', 'C0325', 'E0211', 'W1501']) |