From 51f0597675655ae85dfbce417632f0604728641c Mon Sep 17 00:00:00 2001 From: Andrey Petukhov Date: Wed, 9 Dec 2020 11:58:08 +0300 Subject: [PATCH 1/6] Add case with overwrite indent_chances --- pycodestyle.py | 13 +++++++++++++ testsuite/E12not.py | 23 +++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/pycodestyle.py b/pycodestyle.py index 17fac7a81..dae0b5aee 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -638,6 +638,7 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, hangs = [None] # visual indents indent_chances = {} + indent_chances_rows = {} last_indent = tokens[0][2] visual_indent = None last_token_multiline = False @@ -706,6 +707,9 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, # ignore token lined up with matching one from a # previous line pass + elif isinstance(visual_indent, list) and text in visual_indent: + # issue-953 + pass else: # indent is broken if hang <= 0: @@ -778,6 +782,15 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, if start[1] not in indent_chances: # allow lining up tokens indent_chances[start[1]] = text + else: + None, False, True, str or list + v = indent_chances[start[1]] + # print(indent_chances, text, start[1]) + if not isinstance(v, (bool, type(None))): + if isinstance(v, list): + indent_chances[start[1]].append(text) + else: + indent_chances[start[1]] = [v, text] last_token_multiline = (start[0] != end[0]) if last_token_multiline: diff --git a/testsuite/E12not.py b/testsuite/E12not.py index 2e2366c23..d60ce07db 100644 --- a/testsuite/E12not.py +++ b/testsuite/E12not.py @@ -659,3 +659,26 @@ def f1(): open('/path/to/some/file/being/written', 'w') as file_2, \ open('just-making-sure-more-continuations-also-work'): file_2.write(file_1.read()) + + +aaaa = ( + sqla.session + .pop() +) + + +aaaa5 = ( + sqla.session + .pop() +) + + +verify = ( + sqla.session + .query(table) + .filter( + table.col1 == col1, + table.col2 == col2, + ) + .first() +) From 829a77d46289bdb27b3e3f0cc87b4ca61ce2f273 Mon Sep 17 00:00:00 2001 From: Andrey Petukhov Date: Wed, 9 Dec 2020 12:03:03 +0300 Subject: [PATCH 2/6] Add case with overwrite indent_chances --- pycodestyle.py | 1 - testsuite/E12not.py | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/pycodestyle.py b/pycodestyle.py index dae0b5aee..803a6ae2a 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -638,7 +638,6 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, hangs = [None] # visual indents indent_chances = {} - indent_chances_rows = {} last_indent = tokens[0][2] visual_indent = None last_token_multiline = False diff --git a/testsuite/E12not.py b/testsuite/E12not.py index d60ce07db..6298d5f4f 100644 --- a/testsuite/E12not.py +++ b/testsuite/E12not.py @@ -671,14 +671,3 @@ def f1(): sqla.session .pop() ) - - -verify = ( - sqla.session - .query(table) - .filter( - table.col1 == col1, - table.col2 == col2, - ) - .first() -) From f9bf2a769039939dfa16c12c037fefaaaf093ec2 Mon Sep 17 00:00:00 2001 From: Andrey Petukhov Date: Wed, 9 Dec 2020 12:57:55 +0300 Subject: [PATCH 3/6] Clear code --- pycodestyle.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pycodestyle.py b/pycodestyle.py index 803a6ae2a..6d8abdb6b 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -707,7 +707,6 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, # previous line pass elif isinstance(visual_indent, list) and text in visual_indent: - # issue-953 pass else: # indent is broken @@ -782,7 +781,6 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, # allow lining up tokens indent_chances[start[1]] = text else: - None, False, True, str or list v = indent_chances[start[1]] # print(indent_chances, text, start[1]) if not isinstance(v, (bool, type(None))): From b0d925897d339f8170478b02f8dd2814bc807b6e Mon Sep 17 00:00:00 2001 From: Andrey Petukhov Date: Wed, 9 Dec 2020 13:03:06 +0300 Subject: [PATCH 4/6] Clear code --- pycodestyle.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pycodestyle.py b/pycodestyle.py index 6d8abdb6b..f48c4ddc4 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -782,7 +782,6 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, indent_chances[start[1]] = text else: v = indent_chances[start[1]] - # print(indent_chances, text, start[1]) if not isinstance(v, (bool, type(None))): if isinstance(v, list): indent_chances[start[1]].append(text) From dc43d3c79b6b00bc3a66ef1dc3c078df852c7ecd Mon Sep 17 00:00:00 2001 From: Andrey Petukhov Date: Mon, 14 Dec 2020 10:48:34 +0300 Subject: [PATCH 5/6] added stack --- pycodestyle.py | 49 ++++++++++++++++++++++++--------------------- testsuite/E12not.py | 14 +++++++++++-- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/pycodestyle.py b/pycodestyle.py index f48c4ddc4..1d17c4db2 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -58,6 +58,8 @@ import tokenize import warnings import bisect +from collections import defaultdict +from copy import deepcopy try: from functools import lru_cache @@ -637,7 +639,9 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, # for each depth, memorize the hanging indentation hangs = [None] # visual indents - indent_chances = {} + indent_chances_stack = [] + indent_chances = defaultdict(lambda: set()) + prev_indent_to = float('inf') last_indent = tokens[0][2] visual_indent = None last_token_multiline = False @@ -676,7 +680,8 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, # is there any chance of visual indent? visual_indent = (not close_bracket and hang > 0 and indent_chances.get(start[1])) - + visual_indent = visual_indent or set() + assert isinstance(visual_indent, set) if close_bracket and indent[depth]: # closing bracket for visual indent if start[1] != indent[depth]: @@ -688,7 +693,7 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, if hang_closing: yield start, "E133 closing bracket is missing indentation" elif indent[depth] and start[1] < indent[depth]: - if visual_indent is not True: + if True not in visual_indent: # visual indent is broken yield (start, "E128 continuation line " "under-indented for visual indent") @@ -699,15 +704,13 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, yield (start, "E123 closing bracket does not match " "indentation of opening bracket's line") hangs[depth] = hang - elif visual_indent is True: + elif True in visual_indent: # visual indent is verified indent[depth] = start[1] - elif visual_indent in (text, str): + elif visual_indent & {text, str}: # ignore token lined up with matching one from a # previous line pass - elif isinstance(visual_indent, list) and text in visual_indent: - pass else: # indent is broken if hang <= 0: @@ -729,19 +732,19 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, token_type not in (tokenize.NL, tokenize.COMMENT) and not indent[depth]): indent[depth] = start[1] - indent_chances[start[1]] = True + indent_chances[start[1]].add(True) if verbose >= 4: print("bracket depth %s indent to %s" % (depth, start[1])) # deal with implicit string concatenation elif (token_type in (tokenize.STRING, tokenize.COMMENT) or text in ('u', 'ur', 'b', 'br')): - indent_chances[start[1]] = str + indent_chances[start[1]].add(str) # visual indent after assert/raise/with elif not row and not depth and text in ["assert", "raise", "with"]: - indent_chances[end[1] + 1] = True + indent_chances[end[1] + 1].add(True) # special case for the "if" statement because len("if (") == 4 elif not indent_chances and not row and not depth and text == 'if': - indent_chances[end[1] + 1] = True + indent_chances[end[1] + 1].add(True) elif text == ':' and line[end[1]:].isspace(): open_rows[depth].append(row) @@ -749,6 +752,7 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, if token_type == tokenize.OP: if text in '([{': depth += 1 + indent_chances_stack.append(deepcopy(indent_chances)) indent.append(0) hangs.append(None) if len(open_rows) == depth: @@ -761,32 +765,31 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, elif text in ')]}' and depth > 0: # parent indents should not be more than this one prev_indent = indent.pop() or last_indent[1] + prev_indent = min(prev_indent_to, prev_indent) + if row > open_rows[depth][0]: + prev_indent_to = prev_indent hangs.pop() for d in range(depth): if indent[d] > prev_indent: indent[d] = 0 + prev_indent_chances = indent_chances + indent_chances = indent_chances_stack.pop() for ind in list(indent_chances): - if ind >= prev_indent: + if ind > prev_indent: del indent_chances[ind] + for ind in list(prev_indent_chances): + if ind < prev_indent and ind not in indent_chances: + indent_chances[ind] = prev_indent_chances[ind] del open_rows[depth + 1:] depth -= 1 if depth: - indent_chances[indent[depth]] = True + indent_chances[indent[depth]].add(True) for idx in range(row, -1, -1): if parens[idx]: parens[idx] -= 1 break assert len(indent) == depth + 1 - if start[1] not in indent_chances: - # allow lining up tokens - indent_chances[start[1]] = text - else: - v = indent_chances[start[1]] - if not isinstance(v, (bool, type(None))): - if isinstance(v, list): - indent_chances[start[1]].append(text) - else: - indent_chances[start[1]] = [v, text] + indent_chances[start[1]].add(text) last_token_multiline = (start[0] != end[0]) if last_token_multiline: diff --git a/testsuite/E12not.py b/testsuite/E12not.py index 6298d5f4f..436c8fa02 100644 --- a/testsuite/E12not.py +++ b/testsuite/E12not.py @@ -663,11 +663,21 @@ def f1(): aaaa = ( sqla.session - .pop() + .query(table) ) aaaa5 = ( sqla.session - .pop() + .query(table) +) + +verify = ( + sqla.session + .query(table) + .filter( + table.col1 == col1, + table.col2 == col2, + ) + .first() ) From 84df00d60c01fe53c9581af7eaee6aab0280bf36 Mon Sep 17 00:00:00 2001 From: Andrey Petukhov Date: Tue, 15 Dec 2020 14:30:40 +0300 Subject: [PATCH 6/6] last_indent stack --- pycodestyle.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pycodestyle.py b/pycodestyle.py index 1d17c4db2..5062cb597 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -641,12 +641,11 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, # visual indents indent_chances_stack = [] indent_chances = defaultdict(lambda: set()) - prev_indent_to = float('inf') - last_indent = tokens[0][2] + last_indent = [tokens[0][2][1]] visual_indent = None last_token_multiline = False # for each depth, memorize the visual indent column - indent = [last_indent[1]] + indent = [last_indent[-1]] if verbose >= 3: print(">>> " + tokens[0][4].rstrip()) @@ -659,7 +658,7 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, if newline: # this is the beginning of a continuation line. - last_indent = start + last_indent.append(start[1]) if verbose >= 3: print("... " + line.rstrip()) @@ -693,7 +692,7 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, if hang_closing: yield start, "E133 closing bracket is missing indentation" elif indent[depth] and start[1] < indent[depth]: - if True not in visual_indent: + if not ({str, True} & visual_indent): # visual indent is broken yield (start, "E128 continuation line " "under-indented for visual indent") @@ -764,10 +763,9 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, (depth, start[1], indent[depth])) elif text in ')]}' and depth > 0: # parent indents should not be more than this one - prev_indent = indent.pop() or last_indent[1] - prev_indent = min(prev_indent_to, prev_indent) + prev_indent = indent.pop() or last_indent[-1] if row > open_rows[depth][0]: - prev_indent_to = prev_indent + pass hangs.pop() for d in range(depth): if indent[d] > prev_indent: