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 custom indent sizes (tab widths) other than 4 #524

Closed
wants to merge 5 commits into from
Closed
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 @@ -157,6 +157,7 @@ Quick help is available on the command line::
--count print total number of errors and warnings to standard
error and set exit code to 1 if total is not null
--max-line-length=n set maximum allowed line length (default: 79)
--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
28 changes: 19 additions & 9 deletions pycodestyle.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
PROJECT_CONFIG = ('setup.cfg', 'tox.ini')
TESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite')
MAX_LINE_LENGTH = 79
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 @@ -371,8 +372,9 @@ def missing_whitespace(logical_line):


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):
r"""Use indent_size (PEP 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 @@ -392,8 +394,9 @@ 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 %d" % indent_size)
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 @@ -402,7 +405,7 @@ def indentation(logical_line, previous_logical, indent_char,


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

Continuation lines should align wrapped elements either vertically
Expand Down Expand Up @@ -441,7 +444,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 @@ -505,7 +509,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 @@ -527,7 +532,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 @@ -1401,6 +1406,7 @@ def __init__(self, filename=None, lines=None,
self._logical_checks = options.logical_checks
self._ast_checks = options.ast_checks
self.max_line_length = options.max_line_length
self.indent_size = options.indent_size
self.multiline = False # in a multiline string?
self.hang_closing = options.hang_closing
self.verbose = options.verbose
Expand Down Expand Up @@ -1958,7 +1964,7 @@ def get_parser(prog='pep8', version=__version__):
usage="%prog [options] input ...")
parser.config_options = [
'exclude', 'filename', 'select', 'ignore', 'max-line-length',
'hang-closing', 'count', 'format', 'quiet', 'show-pep8',
'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")
Expand Down Expand Up @@ -1995,6 +2001,10 @@ def get_parser(prog='pep8', version=__version__):
default=MAX_LINE_LENGTH,
help="set maximum allowed line length "
"(default: %default)")
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 @@ -393,3 +393,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)