summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Nowikowski <godfryd@gmail.com>2014-07-30 05:05:34 +0200
committerMichal Nowikowski <godfryd@gmail.com>2014-07-30 05:05:34 +0200
commit3b7880ad7abca812b83bc91bd380891538032125 (patch)
treec00b6f2701aba4f9dfa8961b50d43dad44a4d56e
parent74230a41d37e2838b027d3a1fbd578e42fad0a0e (diff)
parenta99b0f85c075f43b332901c4a3fac917f7c6e748 (diff)
downloadpylint-3b7880ad7abca812b83bc91bd380891538032125.tar.gz
merge
-rw-r--r--ChangeLog13
-rw-r--r--checkers/format.py31
-rw-r--r--test/functional/line_endings.py4
-rw-r--r--test/functional/line_endings.rc2
-rw-r--r--test/functional/line_endings.txt2
-rw-r--r--test/input/func_abstract_class_instantiated_py30.py66
-rw-r--r--test/input/func_assigning_non_slot.py91
-rw-r--r--test/input/func_bad_slots.py90
-rw-r--r--test/input/func_trailing_whitespace.py2
-rw-r--r--test/test_func.py1
10 files changed, 170 insertions, 132 deletions
diff --git a/ChangeLog b/ChangeLog
index a3f7dd9..abc7e29 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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'])