diff --git a/parso/normalizer.py b/parso/normalizer.py index 96c5d01..509cf6d 100644 --- a/parso/normalizer.py +++ b/parso/normalizer.py @@ -16,6 +16,7 @@ class Normalizer(object): def add_issue(self, code, message, node): issue = Issue(node, code, message) self.issues.append(issue) + return True class NormalizerConfig(object): diff --git a/parso/python/normalizer.py b/parso/python/normalizer.py index 1df8656..5e54845 100644 --- a/parso/python/normalizer.py +++ b/parso/python/normalizer.py @@ -13,10 +13,14 @@ class CompressNormalizer(Normalizer): class Comment(object): - def __init__(self, comment_token, indentation): - self.comment_token = comment_token - self.indentation = indentation - self.start_pos = self.comment_token.start_pos + def __init__(self, comment_part, indentation_part): + self.comment_part = comment_part + self.indentation_part = indentation_part + if indentation_part is None: + self.indentation = '' + else: + self.indentation = indentation_part.value + self.start_pos = self.comment_part.start_pos class WhitespaceInfo(object): @@ -33,19 +37,24 @@ class WhitespaceInfo(object): ''' self.has_backslash = False self.comments = [] - indentation = '' + indentation_part = None for part in parts: if part.type == 'backslash': self.has_backslash = True if part.type == 'comment': - self.comments.append(Comment(part, indentation)) + self.comments.append(Comment(part, indentation_part)) if part.type == 'indentation': - indentation = part.value + indentation_part = part else: - indentation = '' - self.indentation = indentation + indentation_part = None + + if indentation_part is None: + self.indentation = '' + else: + self.indentation = indentation_part.value + self.indentation_part = indentation_part self.newline_count = 2 self.trailing_whitespace = [] @@ -63,6 +72,13 @@ class PEP8Normalizer(Normalizer): self._last_indentation_level = 0 self._on_newline = True + if ' ' in config.indentation: + self._indentation_type = 'spaces' + self._wrong_indentation_char = '\t' + else: + self._indentation_type = 'tabs' + self._wrong_indentation_char = ' ' + @contextmanager def visit_node(self, node): typ = node.type @@ -129,17 +145,25 @@ class PEP8Normalizer(Normalizer): if typ == 'suite': self._indentation_level -= 1 + def _check_tabs_spaces(self, leaf, indentation): + if self._wrong_indentation_char in indentation: + self.add_issue(101, 'Indentation contains ' + self._indentation_type, leaf) + return True + return False + def normalize(self, leaf): info = WhitespaceInfo(leaf) should_be_indenation = self._indentation_level * self._config.indentation if self._on_newline: if info.indentation != should_be_indenation: - self.add_issue(111, 'Indentation is not a multiple of four', leaf) + if not self._check_tabs_spaces(info.indentation_part, info.indentation): + s = '%s %s' % (len(self._config.indentation), self._indentation_type) + self.add_issue(111, 'Indentation is not a multiple of ' + s, leaf) first = True for comment in info.comments: if first and not self._on_newline: - continue + continue first = False actual_len = len(comment.indentation) @@ -154,12 +178,13 @@ class PEP8Normalizer(Normalizer): if comment.indentation == should_be_indenation: self._last_indentation_level = i else: - if actual_len < should_len: - self.add_issue(115, 'Expected an indented block (comment)', comment) - elif actual_len > should_len: - self.add_issue(116, 'Unexpected indentation (comment)', comment) - else: - self.add_issue(114, 'indentation is not a multiple of four (comment)', comment) + if not self._check_tabs_spaces(comment.indentation_part, comment.indentation): + if actual_len < should_len: + self.add_issue(115, 'Expected an indented block (comment)', comment) + elif actual_len > should_len: + self.add_issue(116, 'Unexpected indentation (comment)', comment) + else: + self.add_issue(114, 'indentation is not a multiple of four (comment)', comment) self._on_newline = True diff --git a/parso/python/prefix.py b/parso/python/prefix.py index 9cb4ba3..5757d6f 100644 --- a/parso/python/prefix.py +++ b/parso/python/prefix.py @@ -15,6 +15,14 @@ class PrefixPart(object): return self.start_pos[0] + 1, 0 return self.start_pos[0], self.start_pos[1] + len(self.value) + def __repr__(self): + return '%s(%s, %s, %s)' % ( + self.__class__.__name__, + self.type, + repr(self.value), + self.start_pos + ) + _comment = r'#[^\n\r\f]*' _backslash = r'\\\r?\n' diff --git a/test/normalizer_issue_files/E10.py b/test/normalizer_issue_files/E10.py new file mode 100644 index 0000000..dc93550 --- /dev/null +++ b/test/normalizer_issue_files/E10.py @@ -0,0 +1,44 @@ +for a in 'abc': + for b in 'xyz': + print a # indented with 8 spaces + #: W101:0 + print b # indented with 1 tab +if True: + #: W101:0 + pass + +change_2_log = \ +"""Change 2 by slamb@testclient on 2006/04/13 21:46:23 + + creation +""" + +p4change = { + 2: change_2_log, +} + + +class TestP4Poller(unittest.TestCase): + def setUp(self): + self.setUpGetProcessOutput() + return self.setUpChangeSource() + + def tearDown(self): + pass + +# +if True: + #: E101:0 + foo(1, + 2) + +def test_keys(self): + """areas.json - All regions are accounted for.""" + expected = set([ + u'Norrbotten', + u'V\xe4sterbotten', + ]) +if True: + print(""" + tab at start of this line +""") diff --git a/test/test_normalizer_issues_files.py b/test/test_normalizer_issues_files.py index fbe3173..b738e74 100644 --- a/test/test_normalizer_issues_files.py +++ b/test/test_normalizer_issues_files.py @@ -20,7 +20,7 @@ def collect_errors(code): code, _, add_indent = code.partition(':') column = int(add_indent) - yield "%s@(%s,%s)" % (code, line_nr + 1, column) + yield "%s@(%s,%s)" % (code[1:], line_nr + 1, column) def test_normalizer_issue(normalizer_issue_file): @@ -32,7 +32,7 @@ def test_normalizer_issue(normalizer_issue_file): module = parso.parse(code) issues = module._get_normalizer_issues() - i = set("E%s@(%s,%s)" % (i.code, i.start_pos[0], i.start_pos[1]) for i in issues) + i = set("%s@(%s,%s)" % (i.code, i.start_pos[0], i.start_pos[1]) for i in issues) d = set(desired) assert i == d, dedent(""" Test %r failed (%s of %s passed).