[Jython-checkins] jython: Fixed ABC support, including for Java interfaces.

jim.baker jython-checkins at python.org
Sun Sep 14 05:37:09 CEST 2014


http://hg.python.org/jython/rev/5d0fd036d08b
changeset:   7374:5d0fd036d08b
user:        Jim Baker <jim.baker at rackspace.com>
date:        Sat Sep 13 21:35:36 2014 -0600
summary:
  Fixed ABC support, including for Java interfaces.

No longer skips some collection tests, in part by ensuring dict, list,
set are not Hashable by having __hash__ set to None.

java.util.{Map, List, Set} are now treated as subclasses of the
corresponding Python abstract base classes.

files:
  Lib/_abcoll.py                        |   17 +-
  Lib/test/test_collections.py          |    6 +-
  Lib/test/test_collections_jy.py       |  125 ++++++++++++++
  src/org/python/core/PyDictionary.java |    5 +
  src/org/python/core/PyList.java       |   16 +-
  src/org/python/core/PySet.java        |    4 +
  6 files changed, 162 insertions(+), 11 deletions(-)


diff --git a/Lib/_abcoll.py b/Lib/_abcoll.py
--- a/Lib/_abcoll.py
+++ b/Lib/_abcoll.py
@@ -19,6 +19,8 @@
            "Sequence", "MutableSequence",
            ]
 
+_is_jython = sys.platform.startswith("java")
+
 ### ONE-TRICK PONIES ###
 
 def _hasattr(C, attr):
@@ -82,7 +84,7 @@
     @classmethod
     def __subclasshook__(cls, C):
         if cls is Iterator:
-            if _hasattr(C, "next"):
+            if _hasattr(C, "next") and _hasattr(C, "__iter__"):
                 return True
         return NotImplemented
 
@@ -556,8 +558,7 @@
 
 Sequence.register(tuple)
 Sequence.register(basestring)
-if sys.platform[:4] != "java":
-    Sequence.register(buffer)
+Sequence.register(buffer)
 Sequence.register(xrange)
 
 
@@ -600,3 +601,13 @@
         return self
 
 MutableSequence.register(list)
+
+if _is_jython:
+    from org.python.core import PyFastSequenceIter
+    import java
+
+    MutableSequence.register(java.util.List)
+    MutableMapping.register(java.util.Map)
+    MutableSet.register(java.util.Set)
+    Iterator.register(PyFastSequenceIter)
+
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -295,10 +295,8 @@
         # Check some non-hashables
         non_samples = [list(), set(), dict()]
         for x in non_samples:
-            #FIXME: we need to get __hash__ to be None in non_samples for Jython.
-            pass
-            #self.assertNotIsInstance(x, Hashable)
-            #self.assertFalse(issubclass(type(x), Hashable), repr(type(x)))
+            self.assertNotIsInstance(x, Hashable)
+            self.assertFalse(issubclass(type(x), Hashable), repr(type(x)))
         # Check some hashables
         samples = [None,
                    int(), float(), complex(),
diff --git a/Lib/test/test_collections_jy.py b/Lib/test/test_collections_jy.py
new file mode 100644
--- /dev/null
+++ b/Lib/test/test_collections_jy.py
@@ -0,0 +1,125 @@
+from test import test_support
+from test.test_collections import ABCTestCase
+from collections import (
+    Hashable, Iterable, Iterator,
+    Sized, Container, Callable,
+    Set, MutableSet,
+    Mapping, MutableMapping,
+    Sequence, MutableSequence)
+import sys
+
+import java
+
+
+class TestJavaInterfaces(ABCTestCase):
+
+    def test_Iterable(self):
+        # Check some non-iterables
+        non_samples = [
+            java.lang.Integer(42),
+            java.lang.Long(sys.maxint+1)]
+        for x in non_samples:
+            self.assertNotIsInstance(x, Iterable)
+            self.assertFalse(issubclass(type(x), Iterable), repr(type(x)))
+        # Check some iterables
+        samples = [
+            java.util.HashMap(),
+            java.util.ArrayList(),
+            java.util.LinkedList(),
+            java.util.HashMap().keys(),
+            java.util.HashMap().items(),
+            java.util.HashMap().values()]
+        for x in samples:
+            self.assertIsInstance(x, Iterable)
+            self.assertTrue(issubclass(type(x), Iterable), repr(type(x)))
+
+    def test_Container(self):
+        # Check some objects that are not containers
+        non_samples = [
+            java.lang.String(),
+            java.lang.Integer(42),
+            java.lang.Long(sys.maxint+1)]
+        for x in non_samples:
+            self.assertNotIsInstance(x, Container)
+            self.assertFalse(issubclass(type(x), Container), repr(type(x)))
+        # Check some containers
+        samples = [
+            java.util.HashMap(),
+            java.util.ArrayList(),
+            java.util.LinkedList(),
+            java.util.HashMap().keys(),
+            java.util.HashMap().items(),
+            java.util.HashMap().values()]
+        for x in samples:
+            self.assertIsInstance(x, Container)
+            self.assertTrue(issubclass(type(x), Container), repr(type(x)))
+
+    def test_MutableMapping(self):
+        # Check some objects that do not support MutableMapping 
+        non_samples = [
+            java.util.ArrayList(),
+            java.util.HashMap().keys(),
+            java.util.HashSet(),
+            java.util.LinkedList(),
+            java.util.TreeSet(),
+        ]
+        for x in non_samples:
+            self.assertNotIsInstance(x, MutableMapping)
+            self.assertFalse(issubclass(type(x), MutableMapping), repr(type(x)))
+        # Check some mappables
+        samples = [
+            java.util.HashMap(),
+            java.util.concurrent.ConcurrentSkipListMap(),
+        ]
+        for x in samples:
+            self.assertIsInstance(x, MutableMapping)
+            self.assertTrue(issubclass(type(x), MutableMapping), repr(type(x)))
+
+    def test_MutableSequence(self):
+        # Check some objects that do not support MutableSequence
+        non_samples = [
+            java.util.HashMap(),
+            java.util.HashSet(),
+            java.util.TreeSet(),
+            java.util.concurrent.ConcurrentSkipListMap(),
+        ]
+        for x in non_samples:
+            self.assertNotIsInstance(x, MutableSequence)
+            self.assertFalse(issubclass(type(x), MutableSequence), repr(type(x)))
+        # Check some mappables
+        samples = [
+            java.util.ArrayList(),
+            java.util.LinkedList(),
+            java.util.HashMap().keys(),
+        ]
+        for x in samples:
+            self.assertIsInstance(x, MutableSequence)
+            self.assertTrue(issubclass(type(x), MutableSequence), repr(type(x)))
+
+    def test_MutableSet(self):
+        # Check some objects that are not sets
+        non_samples = [
+            java.util.ArrayList(),
+            java.util.LinkedList(),
+            java.util.HashMap(),
+            java.util.concurrent.ConcurrentSkipListMap(),
+        ]
+        for x in non_samples:
+            self.assertNotIsInstance(x, MutableSet)
+            self.assertFalse(issubclass(type(x), MutableSet), repr(type(x)))
+        # Check some sets
+        samples = [
+            java.util.HashSet(),
+            java.util.TreeSet(),
+        ]
+        for x in samples:
+            self.assertIsInstance(x, MutableSet)
+            self.assertTrue(issubclass(type(x), MutableSet), repr(type(x)))
+
+
+def test_main():
+    test_classes = [TestJavaInterfaces]
+    test_support.run_unittest(*test_classes)
+
+if __name__ == "__main__":
+    test_main()
diff --git a/src/org/python/core/PyDictionary.java b/src/org/python/core/PyDictionary.java
--- a/src/org/python/core/PyDictionary.java
+++ b/src/org/python/core/PyDictionary.java
@@ -16,6 +16,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.python.expose.ExposedClassMethod;
+import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -31,6 +32,10 @@
 public class PyDictionary extends PyObject implements ConcurrentMap {
 
     public static final PyType TYPE = PyType.fromClass(PyDictionary.class);
+    {
+        // Ensure dict is not Hashable
+        TYPE.object___setattr__("__hash__", Py.None);
+    }
 
     private final ConcurrentMap<PyObject, PyObject> internalMap;
 
diff --git a/src/org/python/core/PyList.java b/src/org/python/core/PyList.java
--- a/src/org/python/core/PyList.java
+++ b/src/org/python/core/PyList.java
@@ -3,6 +3,8 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+
+import org.python.expose.ExposedGet;
 import org.python.expose.ExposedMethod;
 import org.python.expose.ExposedNew;
 import org.python.expose.ExposedType;
@@ -23,6 +25,11 @@
 public class PyList extends PySequenceList implements List {
 
     public static final PyType TYPE = PyType.fromClass(PyList.class);
+    {
+        // Ensure list is not Hashable
+        TYPE.object___setattr__("__hash__", Py.None);
+    }
+
     private final List<PyObject> list;
     public volatile int gListAllocatedStatus = -1;
 
@@ -918,12 +925,13 @@
     }
 
     public int hashCode() {
-        return list___hash__();
+        throw Py.TypeError(String.format("unhashable type: '%.200s'", getType().fastGetName()));
     }
 
-    @ExposedMethod(doc = BuiltinDocs.list___hash___doc)
-    final synchronized int list___hash__() {
-        throw Py.TypeError(String.format("unhashable type: '%.200s'", getType().fastGetName()));
+    //@ExposedMethod(doc = BuiltinDocs.list___hash___doc)
+    @ExposedGet(name = "__hash__")
+    public PyObject list___hash__() {
+        return Py.None;
     }
 
     @Override
diff --git a/src/org/python/core/PySet.java b/src/org/python/core/PySet.java
--- a/src/org/python/core/PySet.java
+++ b/src/org/python/core/PySet.java
@@ -13,6 +13,10 @@
 public class PySet extends BaseSet {
 
     public static final PyType TYPE = PyType.fromClass(PySet.class);
+    {
+        // Ensure set is not Hashable
+        TYPE.object___setattr__("__hash__", Py.None);
+    }
 
     public PySet() {
         this(TYPE);

-- 
Repository URL: http://hg.python.org/jython


More information about the Jython-checkins mailing list