Index: src/org/python/antlr/GrammarActions.java =================================================================== --- src/org/python/antlr/GrammarActions.java (revision 7101) +++ src/org/python/antlr/GrammarActions.java (working copy) @@ -63,11 +63,6 @@ String makeFromText(List dots, List names) { StringBuilder d = new StringBuilder(); - if (dots != null) { - for (int i=0;i0, + * then the parent is null. If __name__ does exist and is not a + * package name, the containing package is located. If no such package + * exists and level is -1, the parent is null. If + * level is -1, the parent is the current name. Otherwise, + * level-1 doted parts are stripped from the current name. For + * example, the __name__ "a.b.c" and level 2 would + * return "a.b", if c is a package and would + * return "a", if c is not a package. + * + * @param dict + * the __dict__ of a loaded module + * @param level + * used for relative and absolute imports. -1 means try both, 0 + * means absolute only, positive ints represent the level to look + * upward for a relative path (1 means current package, 2 means + * one level up). See PEP 328 at + * http://www.python.org/dev/peps/pep-0328/ + * + * @return the parent name for a module + */ private static String getParent(PyObject dict, int level) { if (dict == null || level == 0) { + // try an absolute import return null; } PyObject tmp = dict.__finditem__("__name__"); @@ -645,20 +656,25 @@ } String name = tmp.toString(); + // locate the current package tmp = dict.__finditem__("__path__"); - if (tmp != null && tmp instanceof PyList) { - return name.intern(); - } - int dot = name.lastIndexOf('.'); - if (dot == -1) { - if (level > 0) { - throw Py.ValueError("Attempted relative import in non-package"); + if (! (tmp instanceof PyList)) { + // __name__ is not a package name, try one level upwards. + int dot = name.lastIndexOf('.'); + if (dot == -1) { + if (level <= -1) { + // there is no package, perform an absolute search + return null; + } + throw Py.ValueError("Attempted relative import in non-package"); } - return null; + // name should be the package name. + name = name.substring(0, dot); } - name = name.substring(0, dot); - while (--level > 0) { - dot = name.lastIndexOf('.'); + + // walk upwards if required (level >= 2) + while (level-- > 1) { + int dot = name.lastIndexOf('.'); if (dot == -1) { throw Py.ValueError("Attempted relative import beyond toplevel package"); } @@ -779,7 +795,7 @@ */ private static PyObject import_name(String name, boolean top, PyObject modDict, PyObject fromlist, int level) { - if (name.length() == 0) { + if (name.length() == 0 && level <= 0) { throw Py.ValueError("Empty module name"); } PyObject modules = Py.getSystemState().modules; @@ -870,9 +886,17 @@ * Called from jython generated code when a statement like "import spam" is * executed. */ + @Deprecated public static PyObject importOne(String mod, PyFrame frame) { + return importOne(mod, frame, imp.DEFAULT_LEVEL); + } + /** + * Called from jython generated code when a statement like "import spam" is + * executed. + */ + public static PyObject importOne(String mod, PyFrame frame, int level) { PyObject module = __builtin__.__import__(mod, frame.f_globals, frame - .getLocals(), Py.None); + .getLocals(), Py.None, level); return module; } @@ -880,9 +904,17 @@ * Called from jython generated code when a statement like "import spam as * foo" is executed. */ + @Deprecated public static PyObject importOneAs(String mod, PyFrame frame) { + return importOneAs(mod, frame, imp.DEFAULT_LEVEL); + } + /** + * Called from jython generated code when a statement like "import spam as + * foo" is executed. + */ + public static PyObject importOneAs(String mod, PyFrame frame, int level) { PyObject module = __builtin__.__import__(mod, frame.f_globals, frame - .getLocals(), Py.None); + .getLocals(), Py.None, level); int dot = mod.indexOf('.'); while (dot != -1) { int dot2 = mod.indexOf('.', dot + 1); @@ -957,26 +989,17 @@ * Called from jython generated code when a statement like "from spam.eggs * import *" is executed. */ - public static void importAll(String mod, PyFrame frame) { + public static void importAll(String mod, PyFrame frame, int level) { PyObject module = __builtin__.__import__(mod, frame.f_globals, frame - .getLocals(), all); - PyObject names; - boolean filter = true; - if (module instanceof PyJavaPackage) { - names = ((PyJavaPackage) module).fillDir(); - } else { - PyObject __all__ = module.__findattr__("__all__"); - if (__all__ != null) { - names = __all__; - filter = false; - } else { - names = module.__dir__(); - } - } - - loadNames(names, module, frame.getLocals(), filter); + .getLocals(), all, level); + importAll(module, frame); } + @Deprecated + public static void importAll(String mod, PyFrame frame) { + importAll(mod, frame, DEFAULT_LEVEL); + } + public static void importAll(PyObject module, PyFrame frame) { PyObject names; boolean filter = true; Index: src/org/python/core/__builtin__.java =================================================================== --- src/org/python/core/__builtin__.java (revision 7101) +++ src/org/python/core/__builtin__.java (working copy) @@ -1161,8 +1161,16 @@ return null; } - PyObject module = __import__.__call__(new PyObject[] {Py.newString(name), globals, locals, - fromlist, Py.newInteger(level)}); + PyObject[] args; + if (level < 0) { + // for backward compatibility provide only 4 arguments + args = new PyObject[] {Py.newString(name), globals, locals, + fromlist}; + } else { + args = new PyObject[] {Py.newString(name), globals, locals, + fromlist, Py.newInteger(level)}; + } + PyObject module = __import__.__call__(args); return module; } Index: src/org/python/compiler/CodeCompiler.java =================================================================== --- src/org/python/compiler/CodeCompiler.java (revision 7101) +++ src/org/python/compiler/CodeCompiler.java (working copy) @@ -896,6 +896,18 @@ return Exit; } + /** + * Push the import level 0 or -1. + */ + private void defaultImportLevel() { + // already prepared for a future change of DEFAULT_LEVEL + if (module.getFutures().isAbsoluteImportOn() || imp.DEFAULT_LEVEL == 0) { + code.iconst_0(); + } else { + code.iconst_m1(); + } + } + @Override public Object visitImport(Import node) throws Exception { setline(node); @@ -906,8 +918,9 @@ asname = a.getInternalAsname(); code.ldc(name); loadFrame(); + defaultImportLevel(); code.invokestatic(p(imp.class), "importOneAs", sig(PyObject.class, String.class, - PyFrame.class)); + PyFrame.class, Integer.TYPE)); } else { String name = a.getInternalName(); asname = name; @@ -916,8 +929,9 @@ } code.ldc(name); loadFrame(); + defaultImportLevel(); code.invokestatic(p(imp.class), "importOne", sig(PyObject.class, String.class, - PyFrame.class)); + PyFrame.class, Integer.TYPE)); } set(new Name(a, asname, expr_contextType.Store)); } @@ -954,8 +968,9 @@ } loadFrame(); + defaultImportLevel(); code.invokestatic(p(imp.class), "importAll", sig(Void.TYPE, String.class, - PyFrame.class)); + PyFrame.class, Integer.TYPE)); } else { java.util.List fromNames = new ArrayList();//[names.size()]; java.util.List asnames = new ArrayList();//[names.size()]; @@ -973,11 +988,7 @@ loadFrame(); if (node.getInternalLevel() == 0) { - if (module.getFutures().isAbsoluteImportOn()) { - code.iconst_0(); - } else { - code.iconst_m1(); - } + defaultImportLevel(); } else { code.iconst(node.getInternalLevel()); }