reject non-docs strings between future imports (closes #17434)

This commit is contained in:
Benjamin Peterson 2013-03-16 09:15:47 -07:00
parent 694bafa04e
commit 2d6acd2ac2
4 changed files with 28 additions and 11 deletions

View file

@ -0,0 +1,3 @@
from __future__ import absolute_import
"spam, bar, blah"
from __future__ import print_function

View file

@ -82,6 +82,14 @@ class FutureTest(unittest.TestCase):
else: else:
self.fail("expected exception didn't occur") 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): def test_parserhack(self):
# test that the parser.c::future_hack function works as expected # test that the parser.c::future_hack function works as expected
# Note: although this test must pass, it's not testing the original # Note: although this test must pass, it's not testing the original

View file

@ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1?
Core and Builtins 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 - Issue #17117: Import and @importlib.util.set_loader now set __loader__ when
it has a value of None or the attribute doesn't exist. it has a value of None or the attribute doesn't exist.

View file

@ -58,11 +58,14 @@ future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename)
static int static int
future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename) 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)) if (!(mod->kind == Module_kind || mod->kind == Interactive_kind))
return 1; return 1;
if (asdl_seq_LEN(mod->v.Module.body) == 0)
return 1;
/* A subsequent pass will detect future imports that don't /* A subsequent pass will detect future imports that don't
appear at the beginning of the file. There's one case, appear at the beginning of the file. There's one case,
however, that is easier to handle here: A series of imports 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)
but is preceded by a regular import. 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); stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
if (done && s->lineno > prev_line) if (done && s->lineno > prev_line)
@ -99,18 +107,13 @@ future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename)
return 0; return 0;
ff->ff_lineno = s->lineno; ff->ff_lineno = s->lineno;
} }
else else {
done = 1; done = 1;
}
} }
else if (s->kind == Expr_kind && !found_docstring) { else {
expr_ty e = s->v.Expr.value;
if (e->kind != Str_kind)
done = 1;
else
found_docstring = 1;
}
else
done = 1; done = 1;
}
} }
return 1; return 1;
} }