Skip to content
Open
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
24 changes: 24 additions & 0 deletions Lib/test/test_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -3273,6 +3273,30 @@ def fib(n):
except SyntaxError:
self.fail("Indented statement over multiple lines is valid")

@support.subTests("indent", ("\t", " \t", "\t ", " "))
@support.subTests("continuations", (1, 3))
@support.subTests("newline", ("\n", "\r\n"))
@support.subTests("first_statement", (False, True))
def test_continuation_tab_indentation(self, indent, continuations,
newline, first_statement):
lines = ["if True:"]
if not first_statement:
lines.append(f"{indent}pass")
lines.extend([f"{indent}\\"] * continuations)
lines.extend(["pass", f"{indent}pass", "pass", ""])
compile(newline.join(lines), "<test>", "exec")

@support.subTests("indents", (
(" ", "\t"), ("\t", " "),
))
@support.subTests("continuations", (1, 3))
def test_continuation_inconsistent_tabs(self, indents, continuations):
previous, continued = indents
lines = ["if True:", f"{previous}pass"]
lines.extend([f"{continued}\\"] * continuations)
lines.extend(["pass", ""])
self.assertRaises(TabError, compile, "\n".join(lines), "<test>", "exec")

def test_continuation_bad_indentation(self):
# Check that code that breaks indentation across multiple lines raises a syntax error

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix tab indentation checks for lines joined by explicit line continuation.
Consistent tab indentation is accepted and ambiguous mixtures of tabs and
spaces are rejected.
4 changes: 3 additions & 1 deletion Parser/lexer/layout.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ _PyLexer_BeginLine(struct tok_state *tok)
int altcol = 0;
tok->layout.at_bol = 0;
int cont_line_col = 0;
int cont_line_altcol = 0;
for (;;) {
c = tok_nextc(tok);
if (c == ' ') {
Expand All @@ -101,6 +102,7 @@ _PyLexer_BeginLine(struct tok_state *tok)
// using backslashes. This means that if we found a backslash
// preceded by whitespace, **the first one we find** determines
// the level of indentation of whatever comes next.
cont_line_altcol = cont_line_col ? cont_line_altcol : altcol;
cont_line_col = cont_line_col ? cont_line_col : col;
if ((c = _PyLexer_ContinueLine(tok)) == -1) {
return -1;
Expand Down Expand Up @@ -136,7 +138,7 @@ _PyLexer_BeginLine(struct tok_state *tok)
}
if (!blankline && tok->level == 0) {
col = cont_line_col ? cont_line_col : col;
altcol = cont_line_col ? cont_line_col : altcol;
altcol = cont_line_col ? cont_line_altcol : altcol;
if (update_indentation(tok, col, altcol) < 0) {
return -1;
}
Expand Down
Loading