reject non-docs strings between future imports (closes #17434)
diff --git a/Lib/test/badsyntax_future10.py b/Lib/test/badsyntax_future10.py
new file mode 100644
index 0000000..fa5ab67
--- /dev/null
+++ b/Lib/test/badsyntax_future10.py
@@ -0,0 +1,3 @@
+from __future__ import absolute_import
+"spam, bar, blah"
+from __future__ import print_function
diff --git a/Lib/test/test_future.py b/Lib/test/test_future.py
index a0c156f..beac993 100644
--- a/Lib/test/test_future.py
+++ b/Lib/test/test_future.py
@@ -82,6 +82,14 @@
else:
self.fail("expected exception didn't occur")
+ def test_badfuture10(self):
+ try:
+ from test import badsyntax_future10
+ except SyntaxError as msg:
+ self.assertEqual(get_error_location(msg), ("badsyntax_future10", '3'))
+ else:
+ self.fail("expected exception didn't occur")
+
def test_parserhack(self):
# test that the parser.c::future_hack function works as expected
# Note: although this test must pass, it's not testing the original
diff --git a/Misc/NEWS b/Misc/NEWS
index 389be1c..b79e295 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,9 @@
Core and Builtins
-----------------
+- Issue #17434: Properly raise a SyntaxError when a string occurs between future
+ imports.
+
- Issue #17117: Import and @importlib.util.set_loader now set __loader__ when
it has a value of None or the attribute doesn't exist.
diff --git a/Python/future.c b/Python/future.c
index d24ae41..345efb2 100644
--- a/Python/future.c
+++ b/Python/future.c
@@ -58,11 +58,14 @@
static int
future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename)
{
- int i, found_docstring = 0, done = 0, prev_line = 0;
+ int i, done = 0, prev_line = 0;
if (!(mod->kind == Module_kind || mod->kind == Interactive_kind))
return 1;
+ if (asdl_seq_LEN(mod->v.Module.body) == 0)
+ return 1;
+
/* A subsequent pass will detect future imports that don't
appear at the beginning of the file. There's one case,
however, that is easier to handle here: A series of imports
@@ -71,8 +74,13 @@
but is preceded by a regular import.
*/
+ i = 0;
+ stmt_ty first = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
+ if (first->kind == Expr_kind && first->v.Expr.value->kind == Str_kind)
+ i++;
- for (i = 0; i < asdl_seq_LEN(mod->v.Module.body); i++) {
+
+ for (; i < asdl_seq_LEN(mod->v.Module.body); i++) {
stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
if (done && s->lineno > prev_line)
@@ -99,18 +107,13 @@
return 0;
ff->ff_lineno = s->lineno;
}
- else
+ else {
done = 1;
+ }
}
- else if (s->kind == Expr_kind && !found_docstring) {
- expr_ty e = s->v.Expr.value;
- if (e->kind != Str_kind)
- done = 1;
- else
- found_docstring = 1;
- }
- else
+ else {
done = 1;
+ }
}
return 1;
}