diff --git a/docs/intro.rst b/docs/intro.rst index 12f67d7e..373bae39 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -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|] diff --git a/pycodestyle.py b/pycodestyle.py index 70263968..755e5055 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -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', @@ -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. @@ -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") @@ -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 @@ -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 @@ -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 " @@ -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" @@ -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 @@ -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") @@ -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") diff --git a/testsuite/test_api.py b/testsuite/test_api.py index 6549a46c..635d655a 100644 --- a/testsuite/test_api.py +++ b/testsuite/test_api.py @@ -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)