Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for space indents with size other than 4 #970

Merged
merged 1 commit into from
Nov 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ Quick help is available on the command line::
--max-line-length=n set maximum allowed line length (default: 79)
--max-doc-length=n set maximum allowed doc line length and perform these
checks (unchecked if not set)
--indent-size=n set how many spaces make up an indent (default: 4)
--hang-closing hang closing bracket instead of matching indentation of
opening bracket's line
--format=format set the error format [default|pylint|<custom>]
Expand Down
40 changes: 28 additions & 12 deletions pycodestyle.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def lru_cache(maxsize=128): # noqa as it's a fake implementation.
'method': 1,
}
MAX_DOC_LENGTH = 72
INDENT_SIZE = 4
REPORT_FORMAT = {
'default': '%(path)s:%(row)d:%(col)d: %(code)s %(text)s',
'pylint': '%(path)s:%(row)d: [%(code)s] %(text)s',
Expand Down Expand Up @@ -543,8 +544,9 @@ def missing_whitespace(logical_line):

@register_check
def indentation(logical_line, previous_logical, indent_char,
indent_level, previous_indent_level):
r"""Use 4 spaces per indentation level.
indent_level, previous_indent_level,
indent_size, indent_size_str):
r"""Use indent_size (PEP8 says 4) spaces per indentation level.

For really old code that you don't want to mess up, you can continue
to use 8-space tabs.
Expand All @@ -564,8 +566,11 @@ def indentation(logical_line, previous_logical, indent_char,
"""
c = 0 if logical_line else 3
tmpl = "E11%d %s" if logical_line else "E11%d %s (comment)"
if indent_level % 4:
yield 0, tmpl % (1 + c, "indentation is not a multiple of four")
if indent_level % indent_size:
yield 0, tmpl % (
1 + c,
"indentation is not a multiple of " + indent_size_str,
)
indent_expect = previous_logical.endswith(':')
if indent_expect and indent_level <= previous_indent_level:
yield 0, tmpl % (2 + c, "expected an indented block")
Expand All @@ -581,7 +586,8 @@ def indentation(logical_line, previous_logical, indent_char,

@register_check
def continued_indentation(logical_line, tokens, indent_level, hang_closing,
indent_char, noqa, verbose):
indent_char, indent_size, indent_size_str, noqa,
verbose):
r"""Continuation lines indentation.

Continuation lines should align wrapped elements either vertically
Expand Down Expand Up @@ -620,7 +626,8 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing,
indent_next = logical_line.endswith(':')

row = depth = 0
valid_hangs = (4,) if indent_char != '\t' else (4, 8)
valid_hangs = (indent_size,) if indent_char != '\t' \
else (indent_size, indent_size * 2)
# remember how many brackets were opened on each line
parens = [0] * nrows
# relative indents of physical lines
Expand Down Expand Up @@ -685,7 +692,8 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing,
# 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):
elif hanging_indent or (indent_next and
rel_indent[row] == 2 * indent_size):
# hanging indent is verified
if close_bracket and not hang_closing:
yield (start, "E123 closing bracket does not match "
Expand All @@ -708,7 +716,7 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing,
error = "E131", "unaligned for hanging indent"
else:
hangs[depth] = hang
if hang > 4:
if hang > indent_size:
error = "E126", "over-indented for hanging indent"
else:
error = "E121", "under-indented for hanging indent"
Expand Down Expand Up @@ -775,8 +783,8 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing,
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 indent_next and expand_indent(line) == indent_level + indent_size:
pos = (start[0], indent[0] + indent_size)
if visual_indent:
code = "E129 visually indented line"
else:
Expand Down Expand Up @@ -1960,8 +1968,12 @@ def __init__(self, filename=None, lines=None,
self._ast_checks = options.ast_checks
self.max_line_length = options.max_line_length
self.max_doc_length = options.max_doc_length
self.indent_size = options.indent_size
self.multiline = False # in a multiline string?
self.hang_closing = options.hang_closing
self.indent_size = options.indent_size
self.indent_size_str = ({2: 'two', 4: 'four', 8: 'eight'}
.get(self.indent_size, str(self.indent_size)))
self.verbose = options.verbose
self.filename = filename
# Dictionary where a checker can store its custom state.
Expand Down Expand Up @@ -2528,8 +2540,8 @@ def get_parser(prog='pycodestyle', version=__version__):
usage="%prog [options] input ...")
parser.config_options = [
'exclude', 'filename', 'select', 'ignore', 'max-line-length',
'max-doc-length', 'hang-closing', 'count', 'format', 'quiet',
'show-pep8', 'show-source', 'statistics', 'verbose']
'max-doc-length', 'indent-size', 'hang-closing', 'count', 'format',
'quiet', 'show-pep8', 'show-source', 'statistics', 'verbose']
parser.add_option('-v', '--verbose', default=0, action='count',
help="print status messages, or debug with -vv")
parser.add_option('-q', '--quiet', default=0, action='count',
Expand Down Expand Up @@ -2569,6 +2581,10 @@ def get_parser(prog='pycodestyle', version=__version__):
default=None,
help="set maximum allowed doc line length and perform "
"these checks (unchecked if not set)")
parser.add_option('--indent-size', type='int', metavar='n',
default=INDENT_SIZE,
help="set how many spaces make up an indent "
"(default: %default)")
parser.add_option('--hang-closing', action='store_true',
help="hang closing bracket instead of matching "
"indentation of opening bracket's line")
Expand Down
49 changes: 49 additions & 0 deletions testsuite/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,52 @@ def test_styleguide_continuation_line_outdented(self):

# TODO: runner
# TODO: input_file

def test_styleguides_other_indent_size(self):
pycodestyle.register_check(DummyChecker, ['Z701'])
lines = [
'def foo():\n',
' pass\n',
'\n',
'\n',
'def foo_correct():\n',
' pass\n',
'\n',
'\n',
'def bar():\n',
' [1, 2, 3,\n',
' 4, 5, 6,\n',
' ]\n',
'\n',
'\n',
'if (1 in [1, 2, 3]\n',
' and bool(0) is False\n',
' and bool(1) is True):\n',
' pass\n'
]

pep8style = pycodestyle.StyleGuide()
pep8style.options.indent_size = 3
count_errors = pep8style.input_file('stdin', lines=lines)
stdout = sys.stdout.getvalue()
self.assertEqual(count_errors, 4)
expected = (
'stdin:2:5: '
'E111 indentation is not a multiple of 3'
)
self.assertTrue(expected in stdout)
expected = (
'stdin:11:6: '
'E127 continuation line over-indented for visual indent'
)
self.assertTrue(expected in stdout)
expected = (
'stdin:12:6: '
'E124 closing bracket does not match visual indentation'
)
self.assertTrue(expected in stdout)
expected = (
'stdin:17:6: '
'E127 continuation line over-indented for visual indent'
)
self.assertTrue(expected in stdout)