SF patch #1438387, PEP 328: relative and absolute imports. · pythoncapi/cpython@f7f438b · GitHub
Skip to content

Commit f7f438b

Browse files
committed
SF patch #1438387, PEP 328: relative and absolute imports.
- IMPORT_NAME takes an extra argument from the stack: the relativeness of the import. Only passed to __import__ when it's not -1. - __import__() takes an optional 5th argument for the same thing; it __defaults to -1 (old semantics: try relative, then absolute) - 'from . import name' imports name (be it module or regular attribute) from the current module's *package*. Likewise, 'from .module import name' will import name from a sibling to the current module. - Importing from outside a package is not allowed; 'from . import sys' in a toplevel module will not work, nor will 'from .. import sys' in a (single-level) package. - 'from __future__ import absolute_import' will turn on the new semantics for import and from-import: imports will be absolute, except for from-import with dots. Includes tests for regular imports and importhooks, parser changes and a NEWS item, but no compiler-package changes or documentation changes.
1 parent d318863 commit f7f438b

20 files changed

Lines changed: 271 additions & 74 deletions

Grammar/Grammar

Lines changed: 1 addition & 1 deletion

Include/Python-ast.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ struct _stmt {
159159
struct {
160160
identifier module;
161161
asdl_seq *names;
162+
int level;
162163
} ImportFrom;
163164

164165
struct {
@@ -371,8 +372,8 @@ stmt_ty TryFinally(asdl_seq * body, asdl_seq * finalbody, int lineno, PyArena
371372
*arena);
372373
stmt_ty Assert(expr_ty test, expr_ty msg, int lineno, PyArena *arena);
373374
stmt_ty Import(asdl_seq * names, int lineno, PyArena *arena);
374-
stmt_ty ImportFrom(identifier module, asdl_seq * names, int lineno, PyArena
375-
*arena);
375+
stmt_ty ImportFrom(identifier module, asdl_seq * names, int level, int lineno,
376+
PyArena *arena);
376377
stmt_ty Exec(expr_ty body, expr_ty globals, expr_ty locals, int lineno, PyArena
377378
*arena);
378379
stmt_ty Global(asdl_seq * names, int lineno, PyArena *arena);

Include/code.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ typedef struct {
4545
#define CO_GENERATOR_ALLOWED 0x1000
4646
#endif
4747
#define CO_FUTURE_DIVISION 0x2000
48+
#define CO_FUTURE_ABSIMPORT 0x4000 /* absolute import by default */
4849

4950
#define CO_MAXBLOCKS 20 /* Max static block nesting within a function */
5051

Include/compile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ typedef struct {
2222
#define FUTURE_NESTED_SCOPES "nested_scopes"
2323
#define FUTURE_GENERATORS "generators"
2424
#define FUTURE_DIVISION "division"
25+
#define FUTURE_ABSIMPORT "absolute_import"
2526

2627
struct _mod; /* Declare the existence of this type */
2728
PyAPI_FUNC(PyCodeObject *) PyAST_Compile(struct _mod *, const char *,

Include/import.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,16 @@ PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleEx(
1414
PyAPI_FUNC(PyObject *) PyImport_GetModuleDict(void);
1515
PyAPI_FUNC(PyObject *) PyImport_AddModule(const char *name);
1616
PyAPI_FUNC(PyObject *) PyImport_ImportModule(const char *name);
17+
PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevel(char *name,
18+
PyObject *globals, PyObject *locals, PyObject *fromlist, int level);
19+
20+
/* For DLL compatibility */
21+
#undef PyImport_ImportModuleEx
1722
PyAPI_FUNC(PyObject *) PyImport_ImportModuleEx(
1823
char *name, PyObject *globals, PyObject *locals, PyObject *fromlist);
24+
#define PyImport_ImportModuleEx(n, g, l, f) \
25+
PyImport_ImportModuleLevel(n, g, l, f, -1);
26+
1927
PyAPI_FUNC(PyObject *) PyImport_Import(PyObject *name);
2028
PyAPI_FUNC(PyObject *) PyImport_ReloadModule(PyObject *m);
2129
PyAPI_FUNC(void) PyImport_Cleanup(void);

Include/pythonrun.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
extern "C" {
88
#endif
99

10-
#define PyCF_MASK (CO_FUTURE_DIVISION)
10+
#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSIMPORT)
1111
#define PyCF_MASK_OBSOLETE (CO_NESTED)
1212
#define PyCF_SOURCE_IS_UTF8 0x0100
1313
#define PyCF_DONT_IMPLY_DEDENT 0x0200

Lib/__future__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"nested_scopes",
5252
"generators",
5353
"division",
54+
"absolute_import",
5455
]
5556

5657
__all__ = ["all_feature_names"] + all_feature_names
@@ -62,6 +63,7 @@
6263
CO_NESTED = 0x0010 # nested_scopes
6364
CO_GENERATOR_ALLOWED = 0 # generators (obsolete, was 0x1000)
6465
CO_FUTURE_DIVISION = 0x2000 # division
66+
CO_FUTURE_ABSIMPORT = 0x4000 # absolute_import
6567

6668
class _Feature:
6769
def __init__(self, optionalRelease, mandatoryRelease, compiler_flag):
@@ -102,3 +104,7 @@ def __repr__(self):
102104
division = _Feature((2, 2, 0, "alpha", 2),
103105
(3, 0, 0, "alpha", 0),
104106
CO_FUTURE_DIVISION)
107+
108+
absolute_import = _Feature((2, 5, 0, "alpha", 1),
109+
(2, 7, 0, "alpha", 0),
110+
CO_FUTURE_ABSIMPORT)

Lib/test/test_ast.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def run_tests():
145145
('Module', [('TryFinally', [('Pass',)], [('Pass',)])]),
146146
('Module', [('Assert', ('Name', 'v', ('Load',)), None)]),
147147
('Module', [('Import', [('alias', 'sys', None)])]),
148-
('Module', [('ImportFrom', 'sys', [('alias', 'v', None)])]),
148+
('Module', [('ImportFrom', 'sys', [('alias', 'v', None)], 0)]),
149149
('Module', [('Exec', ('Str', 'v'), None, None)]),
150150
('Module', [('Global', ['v'])]),
151151
('Module', [('Expr', ('Num', 1))]),

Lib/test/test_importhooks.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,22 @@ def get_file():
1212
return __file__
1313
"""
1414

15+
absimp = "import sub\n"
16+
relimp = "from . import sub\n"
17+
futimp = "from __future__ import absolute_import\n"
18+
1519
reload_src = test_src+"""\
1620
reloaded = True
1721
"""
1822

1923
test_co = compile(test_src, "<???>", "exec")
2024
reload_co = compile(reload_src, "<???>", "exec")
2125

26+
test2_oldabs_co = compile(absimp + test_src, "<???>", "exec")
27+
test2_newabs_co = compile(futimp + absimp + test_src, "<???>", "exec")
28+
test2_newrel_co = compile(relimp + test_src, "<???>", "exec")
29+
test2_futrel_co = compile(futimp + relimp + test_src, "<???>", "exec")
30+
2231
test_path = "!!!_test_!!!"
2332

2433

@@ -38,6 +47,11 @@ class TestImporter:
3847
"hooktestpackage": (True, test_co),
3948
"hooktestpackage.sub": (True, test_co),
4049
"hooktestpackage.sub.subber": (False, test_co),
50+
"hooktestpackage.oldabs": (False, test2_oldabs_co),
51+
"hooktestpackage.newabs": (False, test2_newabs_co),
52+
"hooktestpackage.newrel": (False, test2_newrel_co),
53+
"hooktestpackage.futrel": (False, test2_futrel_co),
54+
"sub": (False, test_co),
4155
"reloadmodule": (False, test_co),
4256
}
4357

@@ -176,6 +190,32 @@ def doTestImports(self, importer=None):
176190
TestImporter.modules['reloadmodule'] = (False, reload_co)
177191
reload(reloadmodule)
178192
self.failUnless(hasattr(reloadmodule,'reloaded'))
193+
194+
import hooktestpackage.oldabs
195+
self.assertEqual(hooktestpackage.oldabs.get_name(),
196+
"hooktestpackage.oldabs")
197+
self.assertEqual(hooktestpackage.oldabs.sub,
198+
hooktestpackage.sub)
199+
200+
import hooktestpackage.newrel
201+
self.assertEqual(hooktestpackage.newrel.get_name(),
202+
"hooktestpackage.newrel")
203+
self.assertEqual(hooktestpackage.newrel.sub,
204+
hooktestpackage.sub)
205+
206+
import hooktestpackage.futrel
207+
self.assertEqual(hooktestpackage.futrel.get_name(),
208+
"hooktestpackage.futrel")
209+
self.assertEqual(hooktestpackage.futrel.sub,
210+
hooktestpackage.sub)
211+
212+
import sub
213+
self.assertEqual(sub.get_name(), "sub")
214+
215+
import hooktestpackage.newabs
216+
self.assertEqual(hooktestpackage.newabs.get_name(),
217+
"hooktestpackage.newabs")
218+
self.assertEqual(hooktestpackage.newabs.sub, sub)
179219

180220
def testMetaPath(self):
181221
i = MetaImporter()

Modules/parsermodule.c

Lines changed: 28 additions & 13 deletions

0 commit comments

Comments
 (0)