Skip to content

Commit 7c97dc8

Browse files
gh-118216: Don't consider dotted __future__ imports (#118267)
1 parent 67bba9d commit 7c97dc8

File tree

5 files changed

+26
-2
lines changed

5 files changed

+26
-2
lines changed

Doc/whatsnew/3.13.rst

+4
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ Other Language Changes
288288
class scopes are not inlined into their parent scope. (Contributed by
289289
Jelle Zijlstra in :gh:`109118` and :gh:`118160`.)
290290

291+
* ``from __future__ import ...`` statements are now just normal
292+
relative imports if dots are present before the module name.
293+
(Contributed by Jeremiah Gabriel Pascual in :gh:`118216`.)
294+
291295

292296
New Modules
293297
===========

Lib/test/test_future_stmt/test_future.py

+19
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,25 @@ def test_syntactical_future_repl(self):
203203
out = kill_python(p)
204204
self.assertNotIn(b'SyntaxError: invalid syntax', out)
205205

206+
def test_future_dotted_import(self):
207+
with self.assertRaises(ImportError):
208+
exec("from .__future__ import spam")
209+
210+
code = dedent(
211+
"""
212+
from __future__ import print_function
213+
from ...__future__ import ham
214+
"""
215+
)
216+
with self.assertRaises(ImportError):
217+
exec(code)
218+
219+
code = """
220+
from .__future__ import nested_scopes
221+
from __future__ import barry_as_FLUFL
222+
"""
223+
self.assertSyntaxError(code, lineno=2)
224+
206225
class AnnotationsFutureTestCase(unittest.TestCase):
207226
template = dedent(
208227
"""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Don't consider :mod:`__future__` imports with dots before the module name.

Python/compile.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -3849,7 +3849,7 @@ compiler_from_import(struct compiler *c, stmt_ty s)
38493849
}
38503850

38513851
if (location_is_after(LOC(s), c->c_future.ff_location) &&
3852-
s->v.ImportFrom.module &&
3852+
s->v.ImportFrom.module && s->v.ImportFrom.level == 0 &&
38533853
_PyUnicode_EqualToASCIIString(s->v.ImportFrom.module, "__future__"))
38543854
{
38553855
Py_DECREF(names);

Python/future.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ future_parse(_PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
7777
* are another future statement and a doc string.
7878
*/
7979

80-
if (s->kind == ImportFrom_kind) {
80+
if (s->kind == ImportFrom_kind && s->v.ImportFrom.level == 0) {
8181
identifier modname = s->v.ImportFrom.module;
8282
if (modname &&
8383
_PyUnicode_EqualToASCIIString(modname, "__future__")) {

0 commit comments

Comments
 (0)