From: <zy...@us...> - 2010-08-24 13:14:30
|
Revision: 7102 http://jython.svn.sourceforge.net/jython/?rev=7102&view=rev Author: zyasoft Date: 2010-08-24 13:14:24 +0000 (Tue, 24 Aug 2010) Log Message: ----------- Fixes incomplete implementation of relative imports for PEP328, which could cause a NPE. Thanks Anselm Kruis! Modified Paths: -------------- trunk/jython/ACKNOWLEDGMENTS trunk/jython/NEWS trunk/jython/src/org/python/antlr/GrammarActions.java trunk/jython/src/org/python/compiler/CodeCompiler.java trunk/jython/src/org/python/core/__builtin__.java trunk/jython/src/org/python/core/imp.java Modified: trunk/jython/ACKNOWLEDGMENTS =================================================================== --- trunk/jython/ACKNOWLEDGMENTS 2010-08-22 06:39:22 UTC (rev 7101) +++ trunk/jython/ACKNOWLEDGMENTS 2010-08-24 13:14:24 UTC (rev 7102) @@ -92,6 +92,7 @@ Costantino Cerbo Alex Gr\xF6nholm Jonathan Feinberg + Anselm Kruis Local Variables: mode: indented-text Modified: trunk/jython/NEWS =================================================================== --- trunk/jython/NEWS 2010-08-22 06:39:22 UTC (rev 7101) +++ trunk/jython/NEWS 2010-08-24 13:14:24 UTC (rev 7102) @@ -2,6 +2,7 @@ Jython 2.5.2b2 Bugs Fixed + - [ 1648 ] Incomplete implementation of pep328 for relative imports - [ 1611 ] Jython bytecode violated JLS, causing NPE on Sun's JVM when using -Xcomp option - [ 1643 ] Tools subdirectory still exists in trunk - [ 1455 ] Classes loaded dynamically from sys.path do not have their package defined Modified: trunk/jython/src/org/python/antlr/GrammarActions.java =================================================================== --- trunk/jython/src/org/python/antlr/GrammarActions.java 2010-08-22 06:39:22 UTC (rev 7101) +++ trunk/jython/src/org/python/antlr/GrammarActions.java 2010-08-24 13:14:24 UTC (rev 7102) @@ -63,11 +63,6 @@ String makeFromText(List dots, List<Name> names) { StringBuilder d = new StringBuilder(); - if (dots != null) { - for (int i=0;i<dots.size();i++) { - d.append("."); - } - } d.append(PythonTree.dottedNameListToString(names)); return d.toString(); } @@ -80,7 +75,9 @@ result.add(new Name(tok, tok.getText(), expr_contextType.Load)); } } - result.addAll(names); + if (null != names) { + result.addAll(names); + } return result; } Modified: trunk/jython/src/org/python/compiler/CodeCompiler.java =================================================================== --- trunk/jython/src/org/python/compiler/CodeCompiler.java 2010-08-22 06:39:22 UTC (rev 7101) +++ trunk/jython/src/org/python/compiler/CodeCompiler.java 2010-08-24 13:14:24 UTC (rev 7102) @@ -896,6 +896,18 @@ return Exit; } + /** + * Push the import level <code>0</code> or <code>-1</code>. + */ + 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<String> fromNames = new ArrayList<String>();//[names.size()]; java.util.List<String> asnames = new ArrayList<String>();//[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()); } Modified: trunk/jython/src/org/python/core/__builtin__.java =================================================================== --- trunk/jython/src/org/python/core/__builtin__.java 2010-08-22 06:39:22 UTC (rev 7101) +++ trunk/jython/src/org/python/core/__builtin__.java 2010-08-24 13:14:24 UTC (rev 7102) @@ -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; } Modified: trunk/jython/src/org/python/core/imp.java =================================================================== --- trunk/jython/src/org/python/core/imp.java 2010-08-22 06:39:22 UTC (rev 7101) +++ trunk/jython/src/org/python/core/imp.java 2010-08-24 13:14:24 UTC (rev 7102) @@ -21,7 +21,7 @@ private static final String UNKNOWN_SOURCEFILE = "<unknown>"; - private static final int APIVersion = 31; + private static final int APIVersion = 32; public static final int NO_MTIME = -1; @@ -621,22 +621,33 @@ return import_first(name, new StringBuilder()); } - /** - * Find the parent module name for a module. If __name__ does not exist in - * the module then the parent is null. If __name__ does exist then the - * __path__ is checked for the parent module. For example, the __name__ - * 'a.b.c' would return 'a.b'. - * - * @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. See PEP 328 at - * http://www.python.org/dev/peps/pep-0328/ - * - * @return the parent name for a module - */ + /** + * Find the parent package name for a module. + * + * If __name__ does not exist in the module or if level is <code>0</code>, + * then the parent is <code>null</code>. If __name__ does exist and is not a + * package name, the containing package is located. If no such package + * exists and level is <code>-1</code>, the parent is <code>null</code>. If + * level is <code>-1</code>, the parent is the current name. Otherwise, + * <code>level-1</code> doted parts are stripped from the current name. For + * example, the __name__ <code>"a.b.c"</code> and level <code>2</code> would + * return <code>"a.b"</code>, if <code>c</code> is a package and would + * return <code>"a"</code>, if <code>c</code> 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; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |