From e30cee9feefc666e87087c7858b1eefa7865eaa0 Mon Sep 17 00:00:00 2001 From: SamriddhiJain Date: Fri, 10 Mar 2017 18:56:27 +0530 Subject: [PATCH 1/8] Added basic test for hanging indents --- pycodestyle.py | 214 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/pycodestyle.py b/pycodestyle.py index 5d8c2ac1..fbe54045 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -640,6 +640,220 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, code = "E125 continuation line" yield pos, "%s with same indent as next logical line" % code +def non_hanging_indentation(logical_line, tokens, indent_level, hang_closing, + indent_char, noqa, verbose): + if(logical_line): + row1 = tokens[0][4].strip('\n') + if(row1.count('(') > row1.count(')') and not row1.endswith(')')): + if(row1.endswith('(')):#hanging indent + continued_indentation(logical_line, tokens, indent_level, hang_closing, + indent_char, noqa, verbose) + else: + yield(0, "Not hanging indent") + +# def non_hanging_indentation(logical_line, tokens, indent_level, hang_closing, +# indent_char, noqa, verbose): +# r"""Continuation lines indentation. + +# Continuation lines should align wrapped elements either vertically +# using Python's implicit line joining inside parentheses, brackets +# and braces, or using a hanging indent. + +# When using a hanging indent these considerations should be applied: +# - there should be no arguments on the first line, and +# - further indentation should be used to clearly distinguish itself as a +# continuation line. + +# Okay: a = (\n) +# E123: a = (\n ) + +# Okay: a = (\n 42) +# E121: a = (\n 42) +# E122: a = (\n42) +# E123: a = (\n 42\n ) +# E124: a = (24,\n 42\n) +# E125: if (\n b):\n pass +# E126: a = (\n 42) +# E127: a = (24,\n 42) +# E128: a = (24,\n 42) +# E129: if (a or\n b):\n pass +# E131: a = (\n 42\n 24) +# """ +# first_row = tokens[0][2][0] +# nrows = 1 + tokens[-1][2][0] - first_row +# if noqa or nrows == 1: +# return + +# # indent_next tells us whether the next block is indented; assuming +# # that it is indented by 4 spaces, then we should not allow 4-space +# # indents on the final continuation line; in turn, some other +# # indents are allowed to have an extra 4 spaces. +# indent_next = logical_line.endswith(':') + +# row = depth = 0 +# valid_hangs = (4,) if indent_char != '\t' else (4, 8) +# # remember how many brackets were opened on each line +# parens = [0] * nrows +# # relative indents of physical lines +# rel_indent = [0] * nrows +# # for each depth, collect a list of opening rows +# open_rows = [[0]] +# # for each depth, memorize the hanging indentation +# hangs = [None] +# # visual indents +# indent_chances = {} +# last_indent = tokens[0][2] +# visual_indent = None +# last_token_multiline = False +# # for each depth, memorize the visual indent column +# indent = [last_indent[1]] +# if verbose >= 3: +# print(">>> " + tokens[0][4].rstrip()) + +# for token_type, text, start, end, line in tokens: + +# newline = row < start[0] - first_row +# if newline: +# row = start[0] - first_row +# newline = not last_token_multiline and token_type not in NEWLINE + +# if newline: +# # this is the beginning of a continuation line. +# last_indent = start +# if verbose >= 3: +# print("... " + line.rstrip()) + +# # record the initial indent. +# rel_indent[row] = expand_indent(line) - indent_level + +# # identify closing bracket +# close_bracket = (token_type == tokenize.OP and text in ']})') + +# # is the indent relative to an opening bracket line? +# for open_row in reversed(open_rows[depth]): +# hang = rel_indent[row] - rel_indent[open_row] +# hanging_indent = hang in valid_hangs +# if hanging_indent: +# break +# if hangs[depth]: +# hanging_indent = (hang == hangs[depth]) +# # is there any chance of visual indent? +# visual_indent = (not close_bracket and hang > 0 and +# indent_chances.get(start[1])) + +# # if(visual_indent): +# # yield (start, "1: Not hanging indent") + +# if close_bracket and indent[depth]: +# # closing bracket for visual indent +# if start[1] != indent[depth]: +# # yield (start, "1: Not hanging indent") +# yield (start, "E124 closing bracket does not match " +# "visual indentation") +# elif close_bracket and not hang: +# # closing bracket matches indentation of opening bracket's line +# 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: +# # visual indent is broken +# yield (start, "E128 continuation line " +# "under-indented for visual indent") +# elif hanging_indent or (indent_next and rel_indent[row] == 8): +# # hanging indent is verified +# if close_bracket and not hang_closing: +# yield (start, "E123 closing bracket does not match " +# "indentation of opening bracket's line") +# hangs[depth] = hang +# elif visual_indent is True: +# # visual indent is verified +# indent[depth] = start[1] +# yield start, "1: Not hanging indent" +# elif visual_indent in (text, str): +# # ignore token lined up with matching one from a previous line +# pass +# else: +# # indent is broken +# if hang <= 0: +# error = "E122", "missing indentation or outdented" +# elif indent[depth]: +# error = "E127", "over-indented for visual indent" +# elif not close_bracket and hangs[depth]: +# error = "E131", "unaligned for hanging indent" +# else: +# hangs[depth] = hang +# if hang > 4: +# error = "E126", "over-indented for hanging indent" +# else: +# error = "E121", "under-indented for hanging indent" +# yield start, "%s continuation line %s" % error + +# # look for visual indenting +# if (parens[row] and +# token_type not in (tokenize.NL, tokenize.COMMENT) and +# not indent[depth]): +# indent[depth] = start[1] +# indent_chances[start[1]] = 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 +# # 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 +# elif text == ':' and line[end[1]:].isspace(): +# open_rows[depth].append(row) + +# # keep track of bracket depth +# if token_type == tokenize.OP: +# if text in '([{': +# depth += 1 +# indent.append(0) +# hangs.append(None) +# if len(open_rows) == depth: +# open_rows.append([]) +# open_rows[depth].append(row) +# parens[row] += 1 +# if verbose >= 4: +# print("bracket depth %s seen, col %s, visual min = %s" % +# (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] +# hangs.pop() +# for d in range(depth): +# if indent[d] > prev_indent: +# indent[d] = 0 +# for ind in list(indent_chances): +# if ind >= prev_indent: +# del indent_chances[ind] +# del open_rows[depth + 1:] +# depth -= 1 +# if depth: +# indent_chances[indent[depth]] = 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 + +# last_token_multiline = (start[0] != end[0]) +# if last_token_multiline: +# rel_indent[end[0] - first_row] = rel_indent[row] + +# if indent_next and expand_indent(line) == indent_level + 4: +# pos = (start[0], indent[0] + 4) +# if visual_indent: +# code = "E129 visually indented line: Not hanging indent" +# else: +# code = "E125 continuation line" +# yield pos, "%s with same indent as next logical line" % code + def whitespace_before_parameters(logical_line, tokens): r"""Avoid extraneous whitespace. From 33f88df84d26a84c33cb9e7df0484626a8395e36 Mon Sep 17 00:00:00 2001 From: SamriddhiJain Date: Fri, 10 Mar 2017 18:57:32 +0530 Subject: [PATCH 2/8] added test cases for hanging indents --- testsuite/hangI.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 testsuite/hangI.py diff --git a/testsuite/hangI.py b/testsuite/hangI.py new file mode 100644 index 00000000..b00b42dc --- /dev/null +++ b/testsuite/hangI.py @@ -0,0 +1,42 @@ +# Aligned with opening delimiter. +foo = long_function_name(var_one, var_two, + var_three, var_four) + + +# More indentation included to distinguish this from the rest. +def long_function_name( + var_one, var_two, var_three, + var_four): + print(var_one) + + +# Hanging indents should add a level. +foo = long_function_name( + var_one, var_two, + var_three, var_four) + +# Hanging indents should add a level. +foo = long_function_name( + var_one, + var_two, + var_three, + var_four +) + + +# Arguments on first line forbidden when not using vertical alignment. +foo = long_function_name(var_one, var_two, + var_three, var_four) + + +# Further indentation required as indentation is not distinguishable. +def long_function_name( + var_one, var_two, var_three, + var_four): + print(var_one) + + +if (value1 == 0 and value2 == 0 and + value3 == 'valueX' and value4 == 'valueY' or + value5 > value6): + raise ValueError("test") From f9e559bd538cdda33ea756ade3d959682dcf40a2 Mon Sep 17 00:00:00 2001 From: SamriddhiJain Date: Sun, 12 Mar 2017 16:24:03 +0530 Subject: [PATCH 3/8] Added check for hanging indents --- pycodestyle.py | 237 +++++-------------------------------------------- 1 file changed, 24 insertions(+), 213 deletions(-) diff --git a/pycodestyle.py b/pycodestyle.py index fbe54045..08dba5ce 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -640,219 +640,30 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, code = "E125 continuation line" yield pos, "%s with same indent as next logical line" % code -def non_hanging_indentation(logical_line, tokens, indent_level, hang_closing, - indent_char, noqa, verbose): - if(logical_line): - row1 = tokens[0][4].strip('\n') - if(row1.count('(') > row1.count(')') and not row1.endswith(')')): - if(row1.endswith('(')):#hanging indent - continued_indentation(logical_line, tokens, indent_level, hang_closing, - indent_char, noqa, verbose) - else: - yield(0, "Not hanging indent") - -# def non_hanging_indentation(logical_line, tokens, indent_level, hang_closing, -# indent_char, noqa, verbose): -# r"""Continuation lines indentation. - -# Continuation lines should align wrapped elements either vertically -# using Python's implicit line joining inside parentheses, brackets -# and braces, or using a hanging indent. - -# When using a hanging indent these considerations should be applied: -# - there should be no arguments on the first line, and -# - further indentation should be used to clearly distinguish itself as a -# continuation line. - -# Okay: a = (\n) -# E123: a = (\n ) - -# Okay: a = (\n 42) -# E121: a = (\n 42) -# E122: a = (\n42) -# E123: a = (\n 42\n ) -# E124: a = (24,\n 42\n) -# E125: if (\n b):\n pass -# E126: a = (\n 42) -# E127: a = (24,\n 42) -# E128: a = (24,\n 42) -# E129: if (a or\n b):\n pass -# E131: a = (\n 42\n 24) -# """ -# first_row = tokens[0][2][0] -# nrows = 1 + tokens[-1][2][0] - first_row -# if noqa or nrows == 1: -# return - -# # indent_next tells us whether the next block is indented; assuming -# # that it is indented by 4 spaces, then we should not allow 4-space -# # indents on the final continuation line; in turn, some other -# # indents are allowed to have an extra 4 spaces. -# indent_next = logical_line.endswith(':') - -# row = depth = 0 -# valid_hangs = (4,) if indent_char != '\t' else (4, 8) -# # remember how many brackets were opened on each line -# parens = [0] * nrows -# # relative indents of physical lines -# rel_indent = [0] * nrows -# # for each depth, collect a list of opening rows -# open_rows = [[0]] -# # for each depth, memorize the hanging indentation -# hangs = [None] -# # visual indents -# indent_chances = {} -# last_indent = tokens[0][2] -# visual_indent = None -# last_token_multiline = False -# # for each depth, memorize the visual indent column -# indent = [last_indent[1]] -# if verbose >= 3: -# print(">>> " + tokens[0][4].rstrip()) - -# for token_type, text, start, end, line in tokens: - -# newline = row < start[0] - first_row -# if newline: -# row = start[0] - first_row -# newline = not last_token_multiline and token_type not in NEWLINE - -# if newline: -# # this is the beginning of a continuation line. -# last_indent = start -# if verbose >= 3: -# print("... " + line.rstrip()) - -# # record the initial indent. -# rel_indent[row] = expand_indent(line) - indent_level - -# # identify closing bracket -# close_bracket = (token_type == tokenize.OP and text in ']})') - -# # is the indent relative to an opening bracket line? -# for open_row in reversed(open_rows[depth]): -# hang = rel_indent[row] - rel_indent[open_row] -# hanging_indent = hang in valid_hangs -# if hanging_indent: -# break -# if hangs[depth]: -# hanging_indent = (hang == hangs[depth]) -# # is there any chance of visual indent? -# visual_indent = (not close_bracket and hang > 0 and -# indent_chances.get(start[1])) - -# # if(visual_indent): -# # yield (start, "1: Not hanging indent") - -# if close_bracket and indent[depth]: -# # closing bracket for visual indent -# if start[1] != indent[depth]: -# # yield (start, "1: Not hanging indent") -# yield (start, "E124 closing bracket does not match " -# "visual indentation") -# elif close_bracket and not hang: -# # closing bracket matches indentation of opening bracket's line -# 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: -# # visual indent is broken -# yield (start, "E128 continuation line " -# "under-indented for visual indent") -# elif hanging_indent or (indent_next and rel_indent[row] == 8): -# # hanging indent is verified -# if close_bracket and not hang_closing: -# yield (start, "E123 closing bracket does not match " -# "indentation of opening bracket's line") -# hangs[depth] = hang -# elif visual_indent is True: -# # visual indent is verified -# indent[depth] = start[1] -# yield start, "1: Not hanging indent" -# elif visual_indent in (text, str): -# # ignore token lined up with matching one from a previous line -# pass -# else: -# # indent is broken -# if hang <= 0: -# error = "E122", "missing indentation or outdented" -# elif indent[depth]: -# error = "E127", "over-indented for visual indent" -# elif not close_bracket and hangs[depth]: -# error = "E131", "unaligned for hanging indent" -# else: -# hangs[depth] = hang -# if hang > 4: -# error = "E126", "over-indented for hanging indent" -# else: -# error = "E121", "under-indented for hanging indent" -# yield start, "%s continuation line %s" % error - -# # look for visual indenting -# if (parens[row] and -# token_type not in (tokenize.NL, tokenize.COMMENT) and -# not indent[depth]): -# indent[depth] = start[1] -# indent_chances[start[1]] = 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 -# # 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 -# elif text == ':' and line[end[1]:].isspace(): -# open_rows[depth].append(row) - -# # keep track of bracket depth -# if token_type == tokenize.OP: -# if text in '([{': -# depth += 1 -# indent.append(0) -# hangs.append(None) -# if len(open_rows) == depth: -# open_rows.append([]) -# open_rows[depth].append(row) -# parens[row] += 1 -# if verbose >= 4: -# print("bracket depth %s seen, col %s, visual min = %s" % -# (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] -# hangs.pop() -# for d in range(depth): -# if indent[d] > prev_indent: -# indent[d] = 0 -# for ind in list(indent_chances): -# if ind >= prev_indent: -# del indent_chances[ind] -# del open_rows[depth + 1:] -# depth -= 1 -# if depth: -# indent_chances[indent[depth]] = 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 - -# last_token_multiline = (start[0] != end[0]) -# if last_token_multiline: -# rel_indent[end[0] - first_row] = rel_indent[row] - -# if indent_next and expand_indent(line) == indent_level + 4: -# pos = (start[0], indent[0] + 4) -# if visual_indent: -# code = "E129 visually indented line: Not hanging indent" -# else: -# code = "E125 continuation line" -# yield pos, "%s with same indent as next logical line" % code +def non_hanging_indentation(logical_line, tokens): + + if(logical_line): + opening_brackets = '({[' + closing_brackets = ')}]' + prev_hang = False + line = "" + for token_type, text, start, end, line2 in tokens: + line2 = line2.rstrip('\n') + if(line != line2): + line = line2 + else: + break + + if(not prev_hang): + for index, bracket in enumerate(opening_brackets): + if(line.rfind(bracket) > line.rfind(closing_brackets[index])): #unbalanced opening bracket + if(line.endswith(bracket)): #hanging indent + prev_hang = True + break + else: + yield(0, "Not hanging indent") + else: #check allignment for hanging indent + pass def whitespace_before_parameters(logical_line, tokens): From d86dccc2477101799aa5c18a01c5bffc6012dadb Mon Sep 17 00:00:00 2001 From: SamriddhiJain Date: Sun, 12 Mar 2017 17:09:45 +0530 Subject: [PATCH 4/8] Added error code and comments --- pycodestyle.py | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/pycodestyle.py b/pycodestyle.py index 08dba5ce..12c86006 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -640,30 +640,39 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, code = "E125 continuation line" yield pos, "%s with same indent as next logical line" % code + def non_hanging_indentation(logical_line, tokens): - + r"""Check for hanging indentation + + Raises error whenever indent is vertical indent and not in proper hanging indent format. + When using a hanging indent these considerations should be applied: + - there should be no arguments on the first line, and + - further indentation should be used to clearly distinguish itself as a + continuation line. + + This method checks the first condition, the second will be automatically + checked by continued_indentation. + + Okay: foo = long_function_name(\n var_one, var_two,\n var_three, var_four) + E134: foo = long_function_name(var_one, var_two,\n var_three, var_four) + """ if(logical_line): opening_brackets = '({[' closing_brackets = ')}]' - prev_hang = False - line = "" - for token_type, text, start, end, line2 in tokens: - line2 = line2.rstrip('\n') - if(line != line2): - line = line2 + prev_line = "" + for token_type, text, start, end, line in tokens: + line = line.rstrip('\n') + if(line != prev_line): + prev_line = line else: break - if(not prev_hang): - for index, bracket in enumerate(opening_brackets): - if(line.rfind(bracket) > line.rfind(closing_brackets[index])): #unbalanced opening bracket - if(line.endswith(bracket)): #hanging indent - prev_hang = True - break - else: - yield(0, "Not hanging indent") - else: #check allignment for hanging indent - pass + for index, bracket in enumerate(opening_brackets): + if(prev_line.rfind(bracket) > prev_line.rfind(closing_brackets[index])): #unbalanced opening bracket + if(prev_line.endswith(bracket)): #hanging indent + break #check allignment for hanging indent + else: + yield(0, "E134 Not hanging indent") def whitespace_before_parameters(logical_line, tokens): From d0db73096658ad2bacf4296be7740d72fc8fd65a Mon Sep 17 00:00:00 2001 From: SamriddhiJain Date: Sun, 12 Mar 2017 17:23:58 +0530 Subject: [PATCH 5/8] comment changes --- pycodestyle.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pycodestyle.py b/pycodestyle.py index 12c86006..18e75a32 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -668,9 +668,11 @@ def non_hanging_indentation(logical_line, tokens): break for index, bracket in enumerate(opening_brackets): - if(prev_line.rfind(bracket) > prev_line.rfind(closing_brackets[index])): #unbalanced opening bracket - if(prev_line.endswith(bracket)): #hanging indent - break #check allignment for hanging indent + # unbalanced opening bracket + if(prev_line.rfind(bracket) > prev_line.rfind(closing_brackets[index])): + if(prev_line.endswith(bracket)): + # hanging indent + break # check allignment for hanging indent else: yield(0, "E134 Not hanging indent") From 795bdb49e6ca7a7f174b5db38106079082e193c7 Mon Sep 17 00:00:00 2001 From: Samriddhi Jain Date: Sun, 12 Mar 2017 22:42:28 +0530 Subject: [PATCH 6/8] delete test cases --- testsuite/hangI.py | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 testsuite/hangI.py diff --git a/testsuite/hangI.py b/testsuite/hangI.py deleted file mode 100644 index b00b42dc..00000000 --- a/testsuite/hangI.py +++ /dev/null @@ -1,42 +0,0 @@ -# Aligned with opening delimiter. -foo = long_function_name(var_one, var_two, - var_three, var_four) - - -# More indentation included to distinguish this from the rest. -def long_function_name( - var_one, var_two, var_three, - var_four): - print(var_one) - - -# Hanging indents should add a level. -foo = long_function_name( - var_one, var_two, - var_three, var_four) - -# Hanging indents should add a level. -foo = long_function_name( - var_one, - var_two, - var_three, - var_four -) - - -# Arguments on first line forbidden when not using vertical alignment. -foo = long_function_name(var_one, var_two, - var_three, var_four) - - -# Further indentation required as indentation is not distinguishable. -def long_function_name( - var_one, var_two, var_three, - var_four): - print(var_one) - - -if (value1 == 0 and value2 == 0 and - value3 == 'valueX' and value4 == 'valueY' or - value5 > value6): - raise ValueError("test") From ed4a7a8d27cd67865c0ee559d4d181a63e52c46e Mon Sep 17 00:00:00 2001 From: SamriddhiJain Date: Wed, 15 Mar 2017 17:41:13 +0530 Subject: [PATCH 7/8] implemented unbalanced paranthesis approach for hanging indents detection --- pycodestyle.py | 62 +++++++++++++++++++++++++++++++++----------------- setup.cfg | 2 +- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/pycodestyle.py b/pycodestyle.py index 18e75a32..3f387ac9 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -69,7 +69,7 @@ __version__ = '2.3.1' DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox' -DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503' +DEFAULT_IGNORE = 'E121,E123,E126,E134,E226,E24,E704,W503' try: if sys.platform == 'win32': USER_CONFIG = os.path.expanduser(r'~\.pycodestyle') @@ -644,37 +644,57 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing, def non_hanging_indentation(logical_line, tokens): r"""Check for hanging indentation - Raises error whenever indent is vertical indent and not in proper hanging indent format. + Raises error whenever indent is vertical indent + and not in proper hanging indent format. When using a hanging indent these considerations should be applied: - there should be no arguments on the first line, and - further indentation should be used to clearly distinguish itself as a continuation line. - This method checks the first condition, the second will be automatically + This method checks the first condition, the second will be automatically checked by continued_indentation. - Okay: foo = long_function_name(\n var_one, var_two,\n var_three, var_four) - E134: foo = long_function_name(var_one, var_two,\n var_three, var_four) + Okay: foo = long_function_name(\n var_one, var_two,\n var_three) + E134: foo = long_function_name(var_one, var_two,\n var_three) """ - if(logical_line): + if (logical_line): opening_brackets = '({[' closing_brackets = ')}]' - prev_line = "" - for token_type, text, start, end, line in tokens: - line = line.rstrip('\n') - if(line != prev_line): - prev_line = line - else: - break + reverse = {')': '(', ']': '[', '}': '{'} + token_vals = [[token_type, text] + for token_type, text, start, end, line in tokens] + newline = [index for index, a in enumerate(token_vals) if a[1] == '\n'] + + n_tokens = len(token_vals) + if ((not len(newline)) or (newline[-1] != n_tokens-1)): + newline.append(n_tokens-1) + + start = 0 + # iterate over each line and get the unbalanced paranthesis + for index, end in enumerate(newline): + queue = [] + last_index = end-1 + for j in range(start, end): + if(token_vals[j][1]): + # append unbalanced opening brackets + if (token_vals[j][1] in opening_brackets): + queue.append([j, token_vals[j][1]]) + elif (token_vals[j][1] in closing_brackets): + if (len(queue)): + bracket = queue.pop() + if(reverse[token_vals[j][1]] != bracket[1]): + queue.append(bracket) # not matching brackets + + while (len(queue)): # unbalanced paranthesis + element = queue.pop() + if (token_vals[last_index][1] == element[1]): + last_index = last_index - 1 # valid hanging indent + elif (token_vals[end-1][1] != element[1] and + token_vals[element[0]-1][0] != tokenize.OP): + yield(0, "E134 Not hanging indent") + break - for index, bracket in enumerate(opening_brackets): - # unbalanced opening bracket - if(prev_line.rfind(bracket) > prev_line.rfind(closing_brackets[index])): - if(prev_line.endswith(bracket)): - # hanging indent - break # check allignment for hanging indent - else: - yield(0, "E134 Not hanging indent") + start = end + 1 def whitespace_before_parameters(logical_line, tokens): diff --git a/setup.cfg b/setup.cfg index 803bc10f..37112759 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,5 +3,5 @@ universal = 1 [pycodestyle] select = -ignore = E226,E24 +ignore = E226,E24,E134 max_line_length = 79 From e19f02a631c76c512f0228f00ab7cbcc785d6328 Mon Sep 17 00:00:00 2001 From: SamriddhiJain Date: Wed, 15 Mar 2017 18:27:47 +0530 Subject: [PATCH 8/8] updated option in documentation and made it default ignore --- docs/intro.rst | 2 ++ pycodestyle.py | 2 +- testsuite/test_api.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/intro.rst b/docs/intro.rst index fcdcf724..13f67701 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -251,6 +251,8 @@ This is the current list of error and warning codes: +------------+----------------------------------------------------------------------+ | E133 (*) | closing bracket is missing indentation | +------------+----------------------------------------------------------------------+ +| E134 | not valid hanging indent | ++------------+----------------------------------------------------------------------+ +------------+----------------------------------------------------------------------+ | **E2** | *Whitespace* | +------------+----------------------------------------------------------------------+ diff --git a/pycodestyle.py b/pycodestyle.py index 3f387ac9..619fa388 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -691,7 +691,7 @@ def non_hanging_indentation(logical_line, tokens): last_index = last_index - 1 # valid hanging indent elif (token_vals[end-1][1] != element[1] and token_vals[element[0]-1][0] != tokenize.OP): - yield(0, "E134 Not hanging indent") + yield(0, "E134 not valid hanging indent") break start = end + 1 diff --git a/testsuite/test_api.py b/testsuite/test_api.py index 4d8b7b26..014e489f 100644 --- a/testsuite/test_api.py +++ b/testsuite/test_api.py @@ -182,7 +182,7 @@ def parse_argv(argstring): self.assertEqual(options.select, ()) self.assertEqual( options.ignore, - ('E121', 'E123', 'E126', 'E226', 'E24', 'E704', 'W503') + ('E121', 'E123', 'E126', 'E134', 'E226', 'E24', 'E704', 'W503') ) options = parse_argv('--doctest').options