Skip to content

Commit 2d6acd2

Browse files
committed
reject non-docs strings between future imports (closes #17434)
1 parent 694bafa commit 2d6acd2

File tree

4 files changed

+28
-11
lines changed

4 files changed

+28
-11
lines changed

Lib/test/badsyntax_future10.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from __future__ import absolute_import
2+
"spam, bar, blah"
3+
from __future__ import print_function

Lib/test/test_future.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ def test_badfuture9(self):
8282
else:
8383
self.fail("expected exception didn't occur")
8484

85+
def test_badfuture10(self):
86+
try:
87+
from test import badsyntax_future10
88+
except SyntaxError as msg:
89+
self.assertEqual(get_error_location(msg), ("badsyntax_future10", '3'))
90+
else:
91+
self.fail("expected exception didn't occur")
92+
8593
def test_parserhack(self):
8694
# test that the parser.c::future_hack function works as expected
8795
# Note: although this test must pass, it's not testing the original

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #17434: Properly raise a SyntaxError when a string occurs between future
14+
imports.
15+
1316
- Issue #17117: Import and @importlib.util.set_loader now set __loader__ when
1417
it has a value of None or the attribute doesn't exist.
1518

Python/future.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,14 @@ future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename)
5858
static int
5959
future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename)
6060
{
61-
int i, found_docstring = 0, done = 0, prev_line = 0;
61+
int i, done = 0, prev_line = 0;
6262

6363
if (!(mod->kind == Module_kind || mod->kind == Interactive_kind))
6464
return 1;
6565

66+
if (asdl_seq_LEN(mod->v.Module.body) == 0)
67+
return 1;
68+
6669
/* A subsequent pass will detect future imports that don't
6770
appear at the beginning of the file. There's one case,
6871
however, that is easier to handle here: A series of imports
@@ -71,8 +74,13 @@ future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename)
7174
but is preceded by a regular import.
7275
*/
7376

77+
i = 0;
78+
stmt_ty first = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
79+
if (first->kind == Expr_kind && first->v.Expr.value->kind == Str_kind)
80+
i++;
7481

75-
for (i = 0; i < asdl_seq_LEN(mod->v.Module.body); i++) {
82+
83+
for (; i < asdl_seq_LEN(mod->v.Module.body); i++) {
7684
stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
7785

7886
if (done && s->lineno > prev_line)
@@ -99,18 +107,13 @@ future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename)
99107
return 0;
100108
ff->ff_lineno = s->lineno;
101109
}
102-
else
110+
else {
103111
done = 1;
112+
}
104113
}
105-
else if (s->kind == Expr_kind && !found_docstring) {
106-
expr_ty e = s->v.Expr.value;
107-
if (e->kind != Str_kind)
108-
done = 1;
109-
else
110-
found_docstring = 1;
111-
}
112-
else
114+
else {
113115
done = 1;
116+
}
114117
}
115118
return 1;
116119
}

0 commit comments

Comments
 (0)