[Python-checkins] r42649 - in python/trunk: Grammar/Grammar Include/Python-ast.h Include/code.h Include/compile.h Include/import.h Include/pythonrun.h Lib/__future__.py Lib/test/test_ast.py Lib/test/test_importhooks.py Modules/parsermodule.c Parser/Python.asdl Python/Python-ast.c Python/ast.c Python/bltinmodule.c Python/ceval.c Python/codecs.c Python/compile.c Python/future.c Python/graminit.c Python/import.c

thomas.wouters python-checkins at python.org
Tue Feb 28 17:09:49 CET 2006


Author: thomas.wouters
Date: Tue Feb 28 17:09:29 2006
New Revision: 42649

Modified:
   python/trunk/Grammar/Grammar
   python/trunk/Include/Python-ast.h
   python/trunk/Include/code.h
   python/trunk/Include/compile.h
   python/trunk/Include/import.h
   python/trunk/Include/pythonrun.h
   python/trunk/Lib/__future__.py
   python/trunk/Lib/test/test_ast.py
   python/trunk/Lib/test/test_importhooks.py
   python/trunk/Modules/parsermodule.c
   python/trunk/Parser/Python.asdl
   python/trunk/Python/Python-ast.c
   python/trunk/Python/ast.c
   python/trunk/Python/bltinmodule.c
   python/trunk/Python/ceval.c
   python/trunk/Python/codecs.c
   python/trunk/Python/compile.c
   python/trunk/Python/future.c
   python/trunk/Python/graminit.c
   python/trunk/Python/import.c
Log:

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.



Modified: python/trunk/Grammar/Grammar
==============================================================================
--- python/trunk/Grammar/Grammar	(original)
+++ python/trunk/Grammar/Grammar	Tue Feb 28 17:09:29 2006
@@ -59,7 +59,7 @@
 raise_stmt: 'raise' [test [',' test [',' test]]]
 import_stmt: import_name | import_from
 import_name: 'import' dotted_as_names
-import_from: ('from' ('.')* dotted_name
+import_from: ('from' ('.'* dotted_name | '.')
               'import' ('*' | '(' import_as_names ')' | import_as_names))
 import_as_name: NAME [NAME NAME]
 dotted_as_name: dotted_name [NAME NAME]

Modified: python/trunk/Include/Python-ast.h
==============================================================================
--- python/trunk/Include/Python-ast.h	(original)
+++ python/trunk/Include/Python-ast.h	Tue Feb 28 17:09:29 2006
@@ -159,6 +159,7 @@
                 struct {
                         identifier module;
                         asdl_seq *names;
+                        int level;
                 } ImportFrom;
                 
                 struct {
@@ -371,8 +372,8 @@
                    *arena);
 stmt_ty Assert(expr_ty test, expr_ty msg, int lineno, PyArena *arena);
 stmt_ty Import(asdl_seq * names, int lineno, PyArena *arena);
-stmt_ty ImportFrom(identifier module, asdl_seq * names, int lineno, PyArena
-                   *arena);
+stmt_ty ImportFrom(identifier module, asdl_seq * names, int level, int lineno,
+                   PyArena *arena);
 stmt_ty Exec(expr_ty body, expr_ty globals, expr_ty locals, int lineno, PyArena
              *arena);
 stmt_ty Global(asdl_seq * names, int lineno, PyArena *arena);

Modified: python/trunk/Include/code.h
==============================================================================
--- python/trunk/Include/code.h	(original)
+++ python/trunk/Include/code.h	Tue Feb 28 17:09:29 2006
@@ -45,6 +45,7 @@
 #define CO_GENERATOR_ALLOWED    0x1000
 #endif
 #define CO_FUTURE_DIVISION    	0x2000
+#define CO_FUTURE_ABSIMPORT	0x4000 /* absolute import by default */
 
 #define CO_MAXBLOCKS 20 /* Max static block nesting within a function */
 

Modified: python/trunk/Include/compile.h
==============================================================================
--- python/trunk/Include/compile.h	(original)
+++ python/trunk/Include/compile.h	Tue Feb 28 17:09:29 2006
@@ -22,6 +22,7 @@
 #define FUTURE_NESTED_SCOPES "nested_scopes"
 #define FUTURE_GENERATORS "generators"
 #define FUTURE_DIVISION "division"
+#define FUTURE_ABSIMPORT "absolute_import"
 
 struct _mod; /* Declare the existence of this type */
 PyAPI_FUNC(PyCodeObject *) PyAST_Compile(struct _mod *, const char *,

Modified: python/trunk/Include/import.h
==============================================================================
--- python/trunk/Include/import.h	(original)
+++ python/trunk/Include/import.h	Tue Feb 28 17:09:29 2006
@@ -14,8 +14,16 @@
 PyAPI_FUNC(PyObject *) PyImport_GetModuleDict(void);
 PyAPI_FUNC(PyObject *) PyImport_AddModule(const char *name);
 PyAPI_FUNC(PyObject *) PyImport_ImportModule(const char *name);
+PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevel(char *name,
+	PyObject *globals, PyObject *locals, PyObject *fromlist, int level);
+
+/* For DLL compatibility */
+#undef PyImport_ImportModuleEx
 PyAPI_FUNC(PyObject *) PyImport_ImportModuleEx(
 	char *name, PyObject *globals, PyObject *locals, PyObject *fromlist);
+#define PyImport_ImportModuleEx(n, g, l, f) \
+	PyImport_ImportModuleLevel(n, g, l, f, -1);
+
 PyAPI_FUNC(PyObject *) PyImport_Import(PyObject *name);
 PyAPI_FUNC(PyObject *) PyImport_ReloadModule(PyObject *m);
 PyAPI_FUNC(void) PyImport_Cleanup(void);

Modified: python/trunk/Include/pythonrun.h
==============================================================================
--- python/trunk/Include/pythonrun.h	(original)
+++ python/trunk/Include/pythonrun.h	Tue Feb 28 17:09:29 2006
@@ -7,7 +7,7 @@
 extern "C" {
 #endif
 
-#define PyCF_MASK (CO_FUTURE_DIVISION)
+#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSIMPORT)
 #define PyCF_MASK_OBSOLETE (CO_NESTED)
 #define PyCF_SOURCE_IS_UTF8  0x0100
 #define PyCF_DONT_IMPLY_DEDENT 0x0200

Modified: python/trunk/Lib/__future__.py
==============================================================================
--- python/trunk/Lib/__future__.py	(original)
+++ python/trunk/Lib/__future__.py	Tue Feb 28 17:09:29 2006
@@ -51,6 +51,7 @@
     "nested_scopes",
     "generators",
     "division",
+    "absolute_import",
 ]
 
 __all__ = ["all_feature_names"] + all_feature_names
@@ -62,6 +63,7 @@
 CO_NESTED            = 0x0010   # nested_scopes
 CO_GENERATOR_ALLOWED = 0        # generators (obsolete, was 0x1000)
 CO_FUTURE_DIVISION   = 0x2000   # division
+CO_FUTURE_ABSIMPORT  = 0x4000   # absolute_import
 
 class _Feature:
     def __init__(self, optionalRelease, mandatoryRelease, compiler_flag):
@@ -102,3 +104,7 @@
 division = _Feature((2, 2, 0, "alpha", 2),
                     (3, 0, 0, "alpha", 0),
                     CO_FUTURE_DIVISION)
+
+absolute_import = _Feature((2, 5, 0, "alpha", 1),
+                           (2, 7, 0, "alpha", 0),
+                           CO_FUTURE_ABSIMPORT)

Modified: python/trunk/Lib/test/test_ast.py
==============================================================================
--- python/trunk/Lib/test/test_ast.py	(original)
+++ python/trunk/Lib/test/test_ast.py	Tue Feb 28 17:09:29 2006
@@ -145,7 +145,7 @@
 ('Module', [('TryFinally', [('Pass',)], [('Pass',)])]),
 ('Module', [('Assert', ('Name', 'v', ('Load',)), None)]),
 ('Module', [('Import', [('alias', 'sys', None)])]),
-('Module', [('ImportFrom', 'sys', [('alias', 'v', None)])]),
+('Module', [('ImportFrom', 'sys', [('alias', 'v', None)], 0)]),
 ('Module', [('Exec', ('Str', 'v'), None, None)]),
 ('Module', [('Global', ['v'])]),
 ('Module', [('Expr', ('Num', 1))]),

Modified: python/trunk/Lib/test/test_importhooks.py
==============================================================================
--- python/trunk/Lib/test/test_importhooks.py	(original)
+++ python/trunk/Lib/test/test_importhooks.py	Tue Feb 28 17:09:29 2006
@@ -12,6 +12,10 @@
     return __file__
 """
 
+absimp = "import sub\n"
+relimp = "from . import sub\n"
+futimp = "from __future__ import absolute_import\n"
+
 reload_src = test_src+"""\
 reloaded = True
 """
@@ -19,6 +23,11 @@
 test_co = compile(test_src, "<???>", "exec")
 reload_co = compile(reload_src, "<???>", "exec")
 
+test2_oldabs_co = compile(absimp + test_src, "<???>", "exec")
+test2_newabs_co = compile(futimp + absimp + test_src, "<???>", "exec")
+test2_newrel_co = compile(relimp + test_src, "<???>", "exec")
+test2_futrel_co = compile(futimp + relimp + test_src, "<???>", "exec")
+
 test_path = "!!!_test_!!!"
 
 
@@ -38,6 +47,11 @@
         "hooktestpackage": (True, test_co),
         "hooktestpackage.sub": (True, test_co),
         "hooktestpackage.sub.subber": (False, test_co),
+        "hooktestpackage.oldabs": (False, test2_oldabs_co),
+        "hooktestpackage.newabs": (False, test2_newabs_co),
+        "hooktestpackage.newrel": (False, test2_newrel_co),
+        "hooktestpackage.futrel": (False, test2_futrel_co),
+        "sub": (False, test_co),
         "reloadmodule": (False, test_co),
     }
 
@@ -176,6 +190,32 @@
         TestImporter.modules['reloadmodule'] = (False, reload_co)
         reload(reloadmodule)
         self.failUnless(hasattr(reloadmodule,'reloaded'))
+        
+        import hooktestpackage.oldabs
+        self.assertEqual(hooktestpackage.oldabs.get_name(),
+                         "hooktestpackage.oldabs")
+        self.assertEqual(hooktestpackage.oldabs.sub,
+                         hooktestpackage.sub)
+
+        import hooktestpackage.newrel
+        self.assertEqual(hooktestpackage.newrel.get_name(),
+                         "hooktestpackage.newrel")
+        self.assertEqual(hooktestpackage.newrel.sub,
+                         hooktestpackage.sub)
+
+        import hooktestpackage.futrel
+        self.assertEqual(hooktestpackage.futrel.get_name(),
+                         "hooktestpackage.futrel")
+        self.assertEqual(hooktestpackage.futrel.sub,
+                         hooktestpackage.sub)
+        
+        import sub
+        self.assertEqual(sub.get_name(), "sub")
+
+        import hooktestpackage.newabs
+        self.assertEqual(hooktestpackage.newabs.get_name(),
+                         "hooktestpackage.newabs")
+        self.assertEqual(hooktestpackage.newabs.sub, sub)
 
     def testMetaPath(self):
         i = MetaImporter()

Modified: python/trunk/Modules/parsermodule.c
==============================================================================
--- python/trunk/Modules/parsermodule.c	(original)
+++ python/trunk/Modules/parsermodule.c	Tue Feb 28 17:09:29 2006
@@ -1792,27 +1792,42 @@
 		&& validate_dotted_as_names(CHILD(tree, 1)));
 }
 
+/* Helper function to count the number of leading dots in 
+ * 'from ...module import name'
+ */
+static int
+count_from_dots(node *tree)
+{
+        int i;
+        for (i = 0; i < NCH(tree); i++)
+		if (TYPE(CHILD(tree, i)) != DOT)
+			break;
+        return i;
+}
 
-/* 'from' dotted_name 'import' ('*' | '(' import_as_names ')' |
+/* 'from' ('.'* dotted_name | '.') 'import' ('*' | '(' import_as_names ')' |
  *     import_as_names
  */
 static int
 validate_import_from(node *tree)
 {
 	int nch = NCH(tree);
+	int ndots = count_from_dots(tree);
+	int havename = (TYPE(CHILD(tree, ndots + 1)) == dotted_name);
+	int offset = ndots + havename;
 	int res = validate_ntype(tree, import_from)
-		  && (nch >= 4)
-		  && validate_name(CHILD(tree, 0), "from")
-		  && validate_dotted_name(CHILD(tree, 1))
-		  && validate_name(CHILD(tree, 2), "import");
-
-	if (res && TYPE(CHILD(tree, 3)) == LPAR)
-	    res = ((nch == 6)
-		   && validate_lparen(CHILD(tree, 3))
-		   && validate_import_as_names(CHILD(tree, 4))
-		   && validate_rparen(CHILD(tree, 5)));
-	else if (res && TYPE(CHILD(tree, 3)) != STAR)
-	    res = validate_import_as_names(CHILD(tree, 3));
+		&& (nch >= 4 + ndots)
+		&& validate_name(CHILD(tree, 0), "from")
+		&& (!havename || validate_dotted_name(CHILD(tree, ndots + 1)))
+		&& validate_name(CHILD(tree, offset + 1), "import");
+
+	if (res && TYPE(CHILD(tree, offset + 2)) == LPAR)
+	    res = ((nch == offset + 5)
+		   && validate_lparen(CHILD(tree, offset + 2))
+		   && validate_import_as_names(CHILD(tree, offset + 3))
+		   && validate_rparen(CHILD(tree, offset + 4)));
+	else if (res && TYPE(CHILD(tree, offset + 2)) != STAR)
+	    res = validate_import_as_names(CHILD(tree, offset + 2));
 	return (res);
 }
 

Modified: python/trunk/Parser/Python.asdl
==============================================================================
--- python/trunk/Parser/Python.asdl	(original)
+++ python/trunk/Parser/Python.asdl	Tue Feb 28 17:09:29 2006
@@ -34,7 +34,7 @@
 	      | Assert(expr test, expr? msg)
 
 	      | Import(alias* names)
-	      | ImportFrom(identifier module, alias* names)
+	      | ImportFrom(identifier module, alias* names, int? level)
 
 	      -- Doesn't capture requirement that locals must be
 	      -- defined if globals is

Modified: python/trunk/Python/Python-ast.c
==============================================================================
--- python/trunk/Python/Python-ast.c	(original)
+++ python/trunk/Python/Python-ast.c	Tue Feb 28 17:09:29 2006
@@ -120,6 +120,7 @@
 char *ImportFrom_fields[]={
         "module",
         "names",
+        "level",
 };
 PyTypeObject *Exec_type;
 char *Exec_fields[]={
@@ -485,7 +486,7 @@
         Import_type = make_type("Import", stmt_type, Import_fields, 1);
         if (!Import_type) return 0;
         ImportFrom_type = make_type("ImportFrom", stmt_type, ImportFrom_fields,
-                                    2);
+                                    3);
         if (!ImportFrom_type) return 0;
         Exec_type = make_type("Exec", stmt_type, Exec_fields, 3);
         if (!Exec_type) return 0;
@@ -1118,7 +1119,8 @@
 }
 
 stmt_ty
-ImportFrom(identifier module, asdl_seq * names, int lineno, PyArena *arena)
+ImportFrom(identifier module, asdl_seq * names, int level, int lineno, PyArena
+           *arena)
 {
         stmt_ty p;
         if (!module) {
@@ -1134,6 +1136,7 @@
         p->kind = ImportFrom_kind;
         p->v.ImportFrom.module = module;
         p->v.ImportFrom.names = names;
+        p->v.ImportFrom.level = level;
         p->lineno = lineno;
         return p;
 }
@@ -2202,6 +2205,11 @@
                 if (PyObject_SetAttrString(result, "names", value) == -1)
                         goto failed;
                 Py_DECREF(value);
+                value = ast2obj_int(o->v.ImportFrom.level);
+                if (!value) goto failed;
+                if (PyObject_SetAttrString(result, "level", value) == -1)
+                        goto failed;
+                Py_DECREF(value);
                 break;
         case Exec_kind:
                 result = PyType_GenericNew(Exec_type, NULL, NULL);

Modified: python/trunk/Python/ast.c
==============================================================================
--- python/trunk/Python/ast.c	(original)
+++ python/trunk/Python/ast.c	Tue Feb 28 17:09:29 2006
@@ -2171,9 +2171,8 @@
     /*
       import_stmt: import_name | import_from
       import_name: 'import' dotted_as_names
-      import_from: 'from' dotted_name 'import' ('*' | 
-                                                '(' import_as_names ')' | 
-                                                import_as_names)
+      import_from: 'from' ('.'* dotted_name | '.') 'import'
+                          ('*' | '(' import_as_names ')' | import_as_names)
     */
     int i;
     asdl_seq *aliases;
@@ -2197,24 +2196,41 @@
     else if (TYPE(n) == import_from) {
         int n_children;
 	int lineno = LINENO(n);
-	alias_ty mod = alias_for_import_name(c, CHILD(n, 1));
-	if (!mod)
-            return NULL;
-
-        switch (TYPE(CHILD(n, 3))) {
+	int idx, ndots = 0;
+	alias_ty mod = NULL;
+	identifier modname;
+	
+       /* Count the number of dots (for relative imports) and check for the
+          optional module name */
+	for (idx = 1; idx < NCH(n); idx++) {
+	    if (TYPE(CHILD(n, idx)) == dotted_name) {
+	    	mod = alias_for_import_name(c, CHILD(n, idx));
+	    	idx++;
+	    	break;
+	    } else if (TYPE(CHILD(n, idx)) != DOT) {
+	        break;
+	    }
+	    ndots++;
+	}
+	idx++; /* skip over the 'import' keyword */
+        switch (TYPE(CHILD(n, idx))) {
         case STAR:
             /* from ... import * */
-	    n = CHILD(n, 3);
+	    n = CHILD(n, idx);
 	    n_children = 1;
+	    if (ndots) {
+	        ast_error(n, "'import *' not allowed with 'from .'");
+	        return NULL;
+	    }
 	    break;
 	case LPAR:
 	    /* from ... import (x, y, z) */
-	    n = CHILD(n, 4);
+	    n = CHILD(n, idx + 1);
 	    n_children = NCH(n);
 	    break;
 	case import_as_names:
 	    /* from ... import x, y, z */
-	    n = CHILD(n, 3);
+	    n = CHILD(n, idx);
 	    n_children = NCH(n);
             if (n_children % 2 == 0) {
                 ast_error(n, "trailing comma not allowed without"
@@ -2245,7 +2261,12 @@
                 return NULL;
 	    asdl_seq_APPEND(aliases, import_alias);
         }
-	return ImportFrom(mod->name, aliases, lineno, c->c_arena);
+        if (mod != NULL)
+            modname = mod->name;
+        else
+            modname = new_identifier("", c->c_arena);
+        return ImportFrom(modname, aliases, ndots, lineno,
+                          c->c_arena);
     }
     PyErr_Format(PyExc_SystemError,
                  "unknown import statement: starts with command '%s'",

Modified: python/trunk/Python/bltinmodule.c
==============================================================================
--- python/trunk/Python/bltinmodule.c	(original)
+++ python/trunk/Python/bltinmodule.c	Tue Feb 28 17:09:29 2006
@@ -37,11 +37,13 @@
 	PyObject *globals = NULL;
 	PyObject *locals = NULL;
 	PyObject *fromlist = NULL;
+	int level = -1;
 
-	if (!PyArg_ParseTuple(args, "s|OOO:__import__",
-			&name, &globals, &locals, &fromlist))
+	if (!PyArg_ParseTuple(args, "s|OOOi:__import__",
+			&name, &globals, &locals, &fromlist, &level))
 		return NULL;
-	return PyImport_ImportModuleEx(name, globals, locals, fromlist);
+	return PyImport_ImportModuleLevel(name, globals, locals,
+					  fromlist, level);
 }
 
 PyDoc_STRVAR(import_doc,

Modified: python/trunk/Python/ceval.c
==============================================================================
--- python/trunk/Python/ceval.c	(original)
+++ python/trunk/Python/ceval.c	Tue Feb 28 17:09:29 2006
@@ -2023,13 +2023,24 @@
 						"__import__ not found");
 				break;
 			}
+			v = POP();
 			u = TOP();
-			w = PyTuple_Pack(4,
-				    w,
-				    f->f_globals,
-				    f->f_locals == NULL ?
-					  Py_None : f->f_locals,
-				    u);
+			if (PyInt_AsLong(u) != -1 || PyErr_Occurred())
+				w = PyTuple_Pack(5,
+					    w,
+					    f->f_globals,
+					    f->f_locals == NULL ?
+						  Py_None : f->f_locals,
+					    v,
+					    u);
+			else
+				w = PyTuple_Pack(4,
+					    w,
+					    f->f_globals,
+					    f->f_locals == NULL ?
+						  Py_None : f->f_locals,
+					    v);
+			Py_DECREF(v);
 			Py_DECREF(u);
 			if (w == NULL) {
 				u = POP();

Modified: python/trunk/Python/codecs.c
==============================================================================
--- python/trunk/Python/codecs.c	(original)
+++ python/trunk/Python/codecs.c	Tue Feb 28 17:09:29 2006
@@ -831,7 +831,7 @@
 	interp->codec_error_registry == NULL)
 	Py_FatalError("can't initialize codec registry");
 
-    mod = PyImport_ImportModuleEx("encodings", NULL, NULL, NULL);
+    mod = PyImport_ImportModuleLevel("encodings", NULL, NULL, NULL, 0);
     if (mod == NULL) {
 	if (PyErr_ExceptionMatches(PyExc_ImportError)) {
 	    /* Ignore ImportErrors... this is done so that

Modified: python/trunk/Python/compile.c
==============================================================================
--- python/trunk/Python/compile.c	(original)
+++ python/trunk/Python/compile.c	Tue Feb 28 17:09:29 2006
@@ -2452,10 +2452,22 @@
 	   XXX Perhaps change the representation to make this case simpler?
 	 */
 	int i, n = asdl_seq_LEN(s->v.Import.names);
+
 	for (i = 0; i < n; i++) {
 		alias_ty alias = asdl_seq_GET(s->v.Import.names, i);
 		int r;
+		PyObject *level;
+
+		if (c->c_flags && (c->c_flags->cf_flags & CO_FUTURE_ABSIMPORT))
+			level = PyInt_FromLong(0);
+		else
+			level = PyInt_FromLong(-1);
 
+		if (level == NULL)
+			return 0;
+
+		ADDOP_O(c, LOAD_CONST, level, consts);
+		Py_DECREF(level);
 		ADDOP_O(c, LOAD_CONST, Py_None, consts);
 		ADDOP_NAME(c, IMPORT_NAME, alias->name, names);
 
@@ -2488,9 +2500,22 @@
 	int i, n = asdl_seq_LEN(s->v.ImportFrom.names);
 
 	PyObject *names = PyTuple_New(n);
+	PyObject *level;
+	
 	if (!names)
 		return 0;
 
+	if (s->v.ImportFrom.level == 0 && c->c_flags &&
+	    !(c->c_flags->cf_flags & CO_FUTURE_ABSIMPORT))
+		level = PyInt_FromLong(-1);
+	else
+		level = PyInt_FromLong(s->v.ImportFrom.level);
+
+	if (!level) {
+		Py_DECREF(names);
+		return 0;
+	}
+
 	/* build up the names */
 	for (i = 0; i < n; i++) {
 		alias_ty alias = asdl_seq_GET(s->v.ImportFrom.names, i);
@@ -2509,6 +2534,8 @@
 		}
 	}
 
+	ADDOP_O(c, LOAD_CONST, level, consts);
+	Py_DECREF(level);
 	ADDOP_O(c, LOAD_CONST, names, consts);
 	Py_DECREF(names);
 	ADDOP_NAME(c, IMPORT_NAME, s->v.ImportFrom.module, names);

Modified: python/trunk/Python/future.c
==============================================================================
--- python/trunk/Python/future.c	(original)
+++ python/trunk/Python/future.c	Tue Feb 28 17:09:29 2006
@@ -29,6 +29,8 @@
 			continue;
 		} else if (strcmp(feature, FUTURE_DIVISION) == 0) {
 			ff->ff_features |= CO_FUTURE_DIVISION;
+		} else if (strcmp(feature, FUTURE_ABSIMPORT) == 0) {
+			ff->ff_features |= CO_FUTURE_ABSIMPORT;
 		} else if (strcmp(feature, "braces") == 0) {
 			PyErr_SetString(PyExc_SyntaxError,
 					"not a chance");

Modified: python/trunk/Python/graminit.c
==============================================================================
--- python/trunk/Python/graminit.c	(original)
+++ python/trunk/Python/graminit.c	Tue Feb 28 17:09:29 2006
@@ -513,34 +513,45 @@
 	{74, 1},
 };
 static arc arcs_26_1[2] = {
-	{75, 1},
-	{12, 2},
+	{75, 2},
+	{12, 3},
 };
-static arc arcs_26_2[1] = {
-	{72, 3},
+static arc arcs_26_2[3] = {
+	{75, 4},
+	{12, 3},
+	{72, 5},
 };
-static arc arcs_26_3[3] = {
-	{28, 4},
-	{13, 5},
-	{76, 4},
+static arc arcs_26_3[1] = {
+	{72, 5},
 };
-static arc arcs_26_4[1] = {
-	{0, 4},
+static arc arcs_26_4[2] = {
+	{75, 4},
+	{12, 3},
 };
-static arc arcs_26_5[1] = {
+static arc arcs_26_5[3] = {
+	{28, 6},
+	{13, 7},
 	{76, 6},
 };
 static arc arcs_26_6[1] = {
-	{15, 4},
+	{0, 6},
+};
+static arc arcs_26_7[1] = {
+	{76, 8},
+};
+static arc arcs_26_8[1] = {
+	{15, 6},
 };
-static state states_26[7] = {
+static state states_26[9] = {
 	{1, arcs_26_0},
 	{2, arcs_26_1},
-	{1, arcs_26_2},
-	{3, arcs_26_3},
-	{1, arcs_26_4},
-	{1, arcs_26_5},
+	{3, arcs_26_2},
+	{1, arcs_26_3},
+	{2, arcs_26_4},
+	{3, arcs_26_5},
 	{1, arcs_26_6},
+	{1, arcs_26_7},
+	{1, arcs_26_8},
 };
 static arc arcs_27_0[1] = {
 	{19, 1},
@@ -1825,7 +1836,7 @@
 	 "\000\000\000\000\000\000\000\000\000\005\000\000\000\000\000\000\000\000\000\000\000"},
 	{281, "import_name", 0, 3, states_25,
 	 "\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000"},
-	{282, "import_from", 0, 7, states_26,
+	{282, "import_from", 0, 9, states_26,
 	 "\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000"},
 	{283, "import_as_name", 0, 4, states_27,
 	 "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},

Modified: python/trunk/Python/import.c
==============================================================================
--- python/trunk/Python/import.c	(original)
+++ python/trunk/Python/import.c	Tue Feb 28 17:09:29 2006
@@ -57,7 +57,7 @@
        Python 2.5a0: 62091 (with)
 .
 */
-#define MAGIC (62091 | ((long)'\r'<<16) | ((long)'\n'<<24))
+#define MAGIC (62092 | ((long)'\r'<<16) | ((long)'\n'<<24))
 
 /* Magic word as global; note that _PyImport_Init() can change the
    value of this global to accommodate for alterations of how the
@@ -1894,7 +1894,8 @@
 }
 
 /* Forward declarations for helper routines */
-static PyObject *get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen);
+static PyObject *get_parent(PyObject *globals, char *buf,
+			    Py_ssize_t *p_buflen, int level);
 static PyObject *load_next(PyObject *mod, PyObject *altmod,
 			   char **p_name, char *buf, Py_ssize_t *p_buflen);
 static int mark_miss(char *name);
@@ -1905,14 +1906,14 @@
 /* The Magnum Opus of dotted-name import :-) */
 
 static PyObject *
-import_module_ex(char *name, PyObject *globals, PyObject *locals,
-		 PyObject *fromlist)
+import_module_level(char *name, PyObject *globals, PyObject *locals,
+		    PyObject *fromlist, int level)
 {
 	char buf[MAXPATHLEN+1];
 	Py_ssize_t buflen = 0;
 	PyObject *parent, *head, *next, *tail;
 
-	parent = get_parent(globals, buf, &buflen);
+	parent = get_parent(globals, buf, &buflen, level);
 	if (parent == NULL)
 		return NULL;
 
@@ -1951,13 +1952,33 @@
 	return tail;
 }
 
+/* For DLL compatibility */
+#undef PyImport_ImportModuleEx
 PyObject *
 PyImport_ImportModuleEx(char *name, PyObject *globals, PyObject *locals,
 			PyObject *fromlist)
 {
 	PyObject *result;
 	lock_import();
-	result = import_module_ex(name, globals, locals, fromlist);
+	result = import_module_level(name, globals, locals, fromlist, -1);
+	if (unlock_import() < 0) {
+		Py_XDECREF(result);
+		PyErr_SetString(PyExc_RuntimeError,
+				"not holding the import lock");
+		return NULL;
+	}
+	return result;
+}
+#define PyImport_ImportModuleEx(n, g, l, f) \
+	PyImport_ImportModuleLevel(n, g, l, f, -1);
+
+PyObject *
+PyImport_ImportModuleLevel(char *name, PyObject *globals, PyObject *locals,
+			 PyObject *fromlist, int level)
+{
+	PyObject *result;
+	lock_import();
+	result = import_module_level(name, globals, locals, fromlist, level);
 	if (unlock_import() < 0) {
 		Py_XDECREF(result);
 		PyErr_SetString(PyExc_RuntimeError,
@@ -1979,13 +2000,13 @@
    corresponding entry is not found in sys.modules, Py_None is returned.
 */
 static PyObject *
-get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen)
+get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen, int level)
 {
 	static PyObject *namestr = NULL;
 	static PyObject *pathstr = NULL;
 	PyObject *modname, *modpath, *modules, *parent;
 
-	if (globals == NULL || !PyDict_Check(globals))
+	if (globals == NULL || !PyDict_Check(globals) || !level)
 		return Py_None;
 
 	if (namestr == NULL) {
@@ -2014,12 +2035,16 @@
 			return NULL;
 		}
 		strcpy(buf, PyString_AS_STRING(modname));
-		*p_buflen = len;
 	}
 	else {
 		char *start = PyString_AS_STRING(modname);
 		char *lastdot = strrchr(start, '.');
 		size_t len;
+		if (lastdot == NULL && level > 0) {
+			PyErr_SetString(PyExc_ValueError,
+					"Relative importpath too deep");
+			return NULL;
+		}
 		if (lastdot == NULL)
 			return Py_None;
 		len = lastdot - start;
@@ -2030,13 +2055,24 @@
 		}
 		strncpy(buf, start, len);
 		buf[len] = '\0';
-		*p_buflen = len;
 	}
 
+	while (--level > 0) {
+		char *dot = strrchr(buf, '.');
+		if (dot == NULL) {
+			PyErr_SetString(PyExc_ValueError,
+					"Relative importpath too deep");
+			return NULL;
+		}
+		*dot = '\0';
+	}
+	*p_buflen = strlen(buf);
+
 	modules = PyImport_GetModuleDict();
 	parent = PyDict_GetItemString(modules, buf);
 	if (parent == NULL)
-		parent = Py_None;
+		PyErr_Format(PyExc_SystemError,
+				"Parent module '%.200s' not loaded", buf);
 	return parent;
 	/* We expect, but can't guarantee, if parent != None, that:
 	   - parent.__name__ == buf
@@ -2055,6 +2091,13 @@
 	char *p;
 	PyObject *result;
 
+	if (strlen(name) == 0) {
+		/* empty module name only happens in 'from . import' */
+		Py_INCREF(mod);
+		*p_name = NULL;
+		return mod;
+	}
+
 	if (dot == NULL) {
 		*p_name = NULL;
 		len = strlen(name);
@@ -2396,8 +2439,8 @@
 		/* No globals -- use standard builtins, and fake globals */
 		PyErr_Clear();
 
-		builtins = PyImport_ImportModuleEx("__builtin__",
-						   NULL, NULL, NULL);
+		builtins = PyImport_ImportModuleLevel("__builtin__",
+						      NULL, NULL, NULL, 0);
 		if (builtins == NULL)
 			return NULL;
 		globals = Py_BuildValue("{OO}", builtins_str, builtins);


More information about the Python-checkins mailing list