[Jython-checkins] jython: Correct level in relative * imports. Fixes #2158 and #2259.
jeff.allen
jython-checkins at python.org
Mon May 4 23:24:14 CEST 2015
https://hg.python.org/jython/rev/9483b3252bd5
changeset: 7702:9483b3252bd5
user: Jeff Allen <ja.py at farowl.co.uk>
date: Sun May 03 21:24:54 2015 +0100
summary:
Correct level in relative * imports. Fixes #2158 and #2259.
A test is added for "from ...X.Y import *" and failing code is
corrected in the code-generation phase of compilation, so that the
proper value of "level" is obtained. Code is simplified (and should
compile to nothing when imp.DEFAULT_LEVEL == 0 in 3.x).
files:
Lib/test/test_import_pep328.py | 75 ++++++----
NEWS | 1 +
src/org/python/compiler/CodeCompiler.java | 26 +--
3 files changed, 58 insertions(+), 44 deletions(-)
diff --git a/Lib/test/test_import_pep328.py b/Lib/test/test_import_pep328.py
--- a/Lib/test/test_import_pep328.py
+++ b/Lib/test/test_import_pep328.py
@@ -34,6 +34,7 @@
import types
EXPLAIN = False # If True, produce commentary in TestImportFunction
+MAXDOTS = 10 # adjust enthusiasm of dotted tests
def dump_module(m):
"Print values of attributes relevant to import mechanism"
@@ -45,13 +46,19 @@
origImport = __import__
-class TestImportStatementError(exceptions.ImportError):
+class TestImportStatementTell(exceptions.ImportError):
+ # Raised by TestImportStatement.importFunction to tell us how it was called
def __init__(self, args):
+ # Smuggle the arguments of importFunction() through the call stack
+ if EXPLAIN: print "\nimport:"
names = ['name', 'globals', 'locals', 'fromlist', 'level']
self.len = len(args)
for a in args:
n = names.pop(0)
setattr(self, n, a)
+ if EXPLAIN:
+ too_long = not isinstance(a, (int, tuple, str, unicode))
+ print " {:12s}= {}".format(n, a if not too_long else type(a))
for n in names:
setattr(self, n, None)
@@ -69,7 +76,7 @@
def importFunction(*args):
if args[0] == '__future__':
return origImport(*args)
- raise TestImportStatementError(args)
+ raise TestImportStatementTell(args)
importFunction = staticmethod(importFunction)
def setUp(self):
@@ -83,73 +90,79 @@
g = {}
try:
exec statement in g, l
- except TestImportStatementError, e:
+ except TestImportStatementTell, e:
self.assert_(e.globals is g, "globals is changed")
self.assert_(e.locals is l, "locals is changed")
return e
- self.fail("Expected a TestImportStatementError")
+ self.fail("Expected a TestImportStatementTell")
+
+ @staticmethod
+ def dotrange(n=MAXDOTS):
+ "Return a longer sequence of dots in each iteration"
+ for i in range(1, n):
+ yield '.'*i
def testFromDotsOnly(self):
- dots = ''
- for i in range(1, 10):
- dots += '.'
+ for dots in self.dotrange():
a = self.runImport("from %s import (A,B)" % (dots,))
self.assertEqual(a.len, 5)
self.assertEqual(a.name, "")
- self.assertEqual(a.level, i)
+ self.assertEqual(a.level, len(dots))
self.assertEqual(a.fromlist, ('A', 'B'))
def testFromDotsOnlyAs(self):
- dots = ''
- for i in range(1, 10):
- dots += '.'
+ for dots in self.dotrange():
a = self.runImport("from %s import A as B" % (dots,))
self.assertEqual(a.len, 5)
self.assertEqual(a.name, "")
self.assertEqual(a.fromlist, ('A',))
- self.assertEqual(a.level, i)
+ self.assertEqual(a.level, len(dots))
def testFromDotsAndName(self):
- dots = ''
- for i in range(1, 10):
- dots += '.'
+ for dots in self.dotrange():
a = self.runImport("from %sX import A" % (dots,))
self.assertEqual(a.len, 5)
self.assertEqual(a.name, "X")
self.assertEqual(a.fromlist, ('A',))
- self.assertEqual(a.level, i)
+ self.assertEqual(a.level, len(dots))
- def testFromDotsAndDotedName(self):
- dots = ''
- for i in range(1, 10):
- dots += '.'
+ def testFromDotsAndDottedName(self):
+ for dots in self.dotrange():
a = self.runImport("from %sX.Y import A" % (dots,))
self.assertEqual(a.len, 5)
self.assertEqual(a.name, "X.Y")
self.assertEqual(a.fromlist, ('A',))
- self.assertEqual(a.level, i)
+ self.assertEqual(a.level, len(dots))
- def testAbsoluteFromDotedNameAs(self):
+ def testFromDotsAndDottedNameAll(self):
+ for dots in self.dotrange():
+ a = self.runImport("from %sX.Y import *" % (dots,))
+ self.assertEqual(a.len, 5, "level argument elided") # Issue 2158
+ self.assertEqual(a.name, "X.Y")
+ self.assertEqual(a.fromlist, ('*',))
+ self.assertEqual(a.level, len(dots))
+
+ def testAbsoluteFromDottedNameAs(self):
a = self.runImport(self.AI + "from X.Y import A as B")
self.assertEqual(a.len, 5)
self.assertEqual(a.name, "X.Y")
self.assertEqual(a.fromlist, ('A',))
self.assertEqual(a.level, 0)
- def testRelativeOrAbsoluteFromDotedNameAs(self):
+ def testRelativeOrAbsoluteFromDottedNameAs(self):
a = self.runImport("from X.Y import A as B")
self.assertEqual(a.name, "X.Y")
self.assertEqual(a.fromlist, ('A',))
self.assertEqual(a.len, 4)
- def testAbsoluteFromDotedNameAll(self):
+ def testAbsoluteFromDottedNameAll(self):
a = self.runImport(self.AI + "from X.Y import *")
self.assertEqual(a.len, 5)
self.assertEqual(a.name, "X.Y")
self.assertEqual(a.fromlist, ('*',))
self.assertEqual(a.level, 0)
- def testRelativeOrAbsoluteFromDotedNameAll(self):
+ def testRelativeOrAbsoluteFromDottedNameAll(self):
a = self.runImport("from X.Y import *")
self.assertEqual(a.name, "X.Y")
self.assertEqual(a.fromlist, ('*',))
@@ -162,7 +175,7 @@
self.assertEqual(a.fromlist, None)
self.assertEqual(a.level, 0)
- def testAbsoluteImportDotedName(self):
+ def testAbsoluteImportDottedName(self):
a = self.runImport(self.AI + "import X.Y")
self.assertEqual(a.len, 5)
self.assertEqual(a.name, "X.Y")
@@ -175,13 +188,13 @@
self.assertEqual(a.fromlist, None)
self.assertEqual(a.len, 4)
- def testRelativeOrAbsoluteImportDotedName(self):
+ def testRelativeOrAbsoluteImportDottedName(self):
a = self.runImport("import X.Y")
self.assertEqual(a.name, "X.Y")
self.assertEqual(a.fromlist, None)
self.assertEqual(a.len, 4)
- def testAbsoluteImportDotedNameAs(self):
+ def testAbsoluteImportDottedNameAs(self):
a = self.runImport(self.AI + "import X.Y as Z")
self.assertEqual(a.len, 5)
self.assertEqual(a.name, "X.Y")
@@ -484,8 +497,10 @@
test_main = unittest.main
else:
def test_main():
- test_support.run_unittest(TestImportStatement,
- TestImportFunction)
+ test_support.run_unittest(
+ TestImportStatement,
+ TestImportFunction,
+ )
if __name__ == '__main__':
test_main()
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@
Bugs fixed
- [ 2347 ] failures in test_import_pep328 when run with -m
+ - [ 2158, 2259 ] Fixed behaviour of relative from ... import *
Jython 2.7rc3
Bugs fixed
diff --git a/src/org/python/compiler/CodeCompiler.java b/src/org/python/compiler/CodeCompiler.java
--- a/src/org/python/compiler/CodeCompiler.java
+++ b/src/org/python/compiler/CodeCompiler.java
@@ -921,14 +921,16 @@
}
/**
- * Push the import level <code>0</code> or <code>-1</code>.
+ * Return the implied import level, which is different from the argument only if the argument is
+ * zero (no leading dots) meaning try relative then absolute (in Python 2), signified by
+ * returning level <code>-1</code>.
*/
- private void defaultImportLevel() {
+ private int impliedImportLevel(int level) {
// already prepared for a future change of DEFAULT_LEVEL
- if (module.getFutures().isAbsoluteImportOn() || imp.DEFAULT_LEVEL == 0) {
- code.iconst_0();
+ if (imp.DEFAULT_LEVEL == 0 || level != 0 || module.getFutures().isAbsoluteImportOn()) {
+ return level;
} else {
- code.iconst_m1();
+ return imp.DEFAULT_LEVEL;
}
}
@@ -942,7 +944,7 @@
asname = a.getInternalAsname();
code.ldc(name);
loadFrame();
- defaultImportLevel();
+ code.iconst(impliedImportLevel(0));
code.invokestatic(p(imp.class), "importOneAs",
sig(PyObject.class, String.class, PyFrame.class, Integer.TYPE));
} else {
@@ -953,7 +955,7 @@
}
code.ldc(name);
loadFrame();
- defaultImportLevel();
+ code.iconst(impliedImportLevel(0));
code.invokestatic(p(imp.class), "importOne",
sig(PyObject.class, String.class, PyFrame.class, Integer.TYPE));
}
@@ -986,9 +988,10 @@
}
loadFrame();
- defaultImportLevel();
+ code.iconst(impliedImportLevel(node.getInternalLevel()));
code.invokestatic(p(imp.class), "importAll",
sig(Void.TYPE, String.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()];
@@ -1004,12 +1007,7 @@
code.freeLocal(strArray);
loadFrame();
-
- if (node.getInternalLevel() == 0) {
- defaultImportLevel();
- } else {
- code.iconst(node.getInternalLevel());
- }
+ code.iconst(impliedImportLevel(node.getInternalLevel()));
code.invokestatic(
p(imp.class),
"importFrom",
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list