[Jython-checkins] jython: Improve complex MRO handling. (Fixes bjo #2445.)
jeff.allen
jython-checkins at python.org
Mon Mar 18 02:21:14 EDT 2019
https://hg.python.org/jython/rev/3c4f2c14b808
changeset: 8226:3c4f2c14b808
user: Jim Baker <jim.baker at python.org>
date: Sun Mar 17 20:57:18 2019 +0000
summary:
Improve complex MRO handling. (Fixes bjo #2445.)
This change fixes a defect in MRO processing (as posted by Jim). It also adds a
test class (adapted by Jeff) with complex inheritance between its inner classes,
and a regression test that would fail before Jim's patch was applied.
files:
Lib/test/test_java_integration.py | 25 +++-
NEWS | 1 +
src/org/python/core/PyJavaType.java | 25 +++-
tests/java/org/python/tests/mro/TortureMRO.java | 51 ++++++++++
4 files changed, 89 insertions(+), 13 deletions(-)
diff --git a/Lib/test/test_java_integration.py b/Lib/test/test_java_integration.py
--- a/Lib/test/test_java_integration.py
+++ b/Lib/test/test_java_integration.py
@@ -234,6 +234,7 @@
Keywords.with = lambda self: "with"
Keywords.yield = lambda self: "yield"
+
class PyReservedNamesTest(unittest.TestCase):
"Access to reserved words"
@@ -330,6 +331,7 @@
def test_yield(self):
self.assertEquals(self.kws.yield(), "yield")
+
class ImportTest(unittest.TestCase):
def test_bad_input_exception(self):
self.assertRaises(ValueError, __import__, '')
@@ -378,6 +380,13 @@
x = String('test')
self.assertRaises(TypeError, list, x)
+ def test_null_tostring(self):
+ # http://bugs.jython.org/issue1819
+ nts = NullToString()
+ self.assertEqual(repr(nts), '')
+ self.assertEqual(str(nts), '')
+ self.assertEqual(unicode(nts), '')
+
class JavaDelegationTest(unittest.TestCase):
def test_list_delegation(self):
for c in ArrayList, Vector:
@@ -531,6 +540,9 @@
self.assertEquals(7, m.initial)
self.assertEquals(None, m.nonexistent, "Nonexistent fields should be passed on to the Map")
+
+class JavaMROTest(unittest.TestCase):
+
def test_adding_on_interface(self):
GetitemAdder.addPredefined()
class UsesInterfaceMethod(FirstPredefinedGetitem):
@@ -543,13 +555,6 @@
self.assertRaises(TypeError, __import__, "org.python.tests.mro.ConfusedOnImport")
self.assertRaises(TypeError, GetitemAdder.addPostdefined)
- def test_null_tostring(self):
- # http://bugs.jython.org/issue1819
- nts = NullToString()
- self.assertEqual(repr(nts), '')
- self.assertEqual(str(nts), '')
- self.assertEqual(unicode(nts), '')
-
def test_diamond_inheritance_of_iterable_and_map(self):
"""Test deeply nested diamond inheritance of Iterable and Map, as see in some Clojure classes"""
# http://bugs.jython.org/issue1878
@@ -570,6 +575,11 @@
self.assertEqual(set(m), set(["abc", "xyz"]))
self.assertEqual(m["abc"], 42)
+ def test_diamond_lattice_inheritance(self):
+ # http://bugs.jython.org/issue2445
+ from org.python.tests.mro import TortureMRO
+
+
def roundtrip_serialization(obj):
"""Returns a deep copy of an object, via serializing it
@@ -946,6 +956,7 @@
JavaDelegationTest,
JavaReservedNamesTest,
JavaStringTest,
+ JavaMROTest,
JavaWrapperCustomizationTest,
PyReservedNamesTest,
SecurityManagerTest,
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@
Development tip
Bugs fixed
+ - [ 2445 ] Eclipse's DelegatingFeatureMap has MRO conflict
- [ 2732 ] Regression in large module support for pip
- [ GH-131 ] Support Unicode in zxJDBC exceptions.
- [ 2654 ] Imported modules allow access to submodules
diff --git a/src/org/python/core/PyJavaType.java b/src/org/python/core/PyJavaType.java
--- a/src/org/python/core/PyJavaType.java
+++ b/src/org/python/core/PyJavaType.java
@@ -257,7 +257,17 @@
PyList types = new PyList();
Set<Class<?>> proxySet = Generic.set();
for (PyJavaType othertype : conflictedAttributes) {
- if (othertype.modified != null && othertype.modified.contains(method)) {
+ /*
+ * Ignore any pairings of types that are in a superclass/superinterface
+ * relationship with each other. This problem is a false positive that
+ * happens because of the automatic addition of methods so that Java classes
+ * behave more like their corresponding Python types, such as adding sort or
+ * remove. See http://bugs.jython.org/issue2445
+ */
+ if (othertype.modified != null && othertype.modified.contains(method)
+ && !(othertype.getProxyType().isAssignableFrom(type.getProxyType())
+ || type.getProxyType()
+ .isAssignableFrom(othertype.getProxyType()))) {
types.add(othertype);
proxySet.add(othertype.getProxyType());
}
@@ -269,13 +279,16 @@
* __iter__. Annoying but necessary logic. See http://bugs.jython.org/issue1878
*/
if (method.equals("__iter__")
- && proxySet.equals(Generic.set(Iterable.class, Map.class))) {
+ && Generic.set(Iterable.class, Map.class).containsAll(proxySet)) {
continue;
}
- throw Py.TypeError(String.format(
- "Supertypes that share a modified attribute "
- + "have an MRO conflict[attribute=%s, supertypes=%s, type=%s]",
- method, types, this.getName()));
+
+ if (types.size() > 0) {
+ throw Py.TypeError(String.format(
+ "Supertypes that share a modified attribute "
+ + "have an MRO conflict[attribute=%s, supertypes=%s, type=%s]",
+ method, types, this.getName()));
+ }
}
}
}
diff --git a/tests/java/org/python/tests/mro/TortureMRO.java b/tests/java/org/python/tests/mro/TortureMRO.java
new file mode 100644
--- /dev/null
+++ b/tests/java/org/python/tests/mro/TortureMRO.java
@@ -0,0 +1,51 @@
+// Copyright (c) Jython Developers.
+// Licensed to the Python Software Foundation under a Contributor Agreement.
+
+package org.python.tests.mro;
+
+/**
+ * A class providing interface and abstract class relationships that approximate the structure of
+ * org.eclipse.emf.ecore.util.DelegatingFeatureMap, in order to exercise b.j.o issue 2445. The
+ * complex inheritance (more complex than diamond inheritance) confused PyJavaType handling of the
+ * MRO. This class is imported by
+ * {@code test_java_integration.JavaMROTest.test_diamond_lattice_inheritance} as a test.
+ * <p>
+ * An invocation at the prompt (for debugging use), and output before the fix, is:
+ *
+ * <pre>
+ * PS > dist\bin\jython -S -c"from org.python.tests.mro import TortureMRO"
+ * Traceback (most recent call last):
+ * File "<string>", line 1, in <module>
+ * TypeError: Supertypes that share a modified attribute have an MRO
+ * conflict[attribute=sort, supertypes=[<type 'java.util.List'>,
+ * <type 'java.util.AbstractList'>], type=TortureMRO$Target]
+ * </pre>
+ */
+public class TortureMRO {
+
+ interface Entry {} // Was FeatureMap.Entry
+
+ interface Thing {} // Was EStructuralFeature.Setting
+
+ interface EList<E> extends java.util.List<E> {}
+
+ interface IEList<E> extends EList<E> {}
+
+ interface FList extends EList<Entry> {} // Was FeatureMap
+
+ interface FIEListThing extends FList, IEList<Entry>, Thing {} // Was 2 FeatureMap.Internal
+
+ abstract static class AbstractEList<E> extends java.util.AbstractList<E> implements EList<E> {}
+
+ abstract static class DEList<E> extends AbstractEList<E> {}
+
+ interface NList<E> extends EList<E> {}
+
+ abstract static class DNListImpl<E> extends DEList<E> implements NList<E> {}
+
+ abstract static class DNIEListImpl<E> extends DNListImpl<E> implements IEList<E> {}
+
+ abstract static class DNIEListThing<E> extends DNIEListImpl<E> implements Thing {}
+
+ public abstract static class Target extends DNIEListThing<Entry> implements FIEListThing {}
+}
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list