[Jython-checkins] jython: Convert iterators to both Object[] and primitive variants. Fixes #2279

jim.baker jython-checkins at python.org
Wed Jan 6 20:40:28 EST 2016


https://hg.python.org/jython/rev/1e7c082d089d
changeset:   7853:1e7c082d089d
user:        Jim Baker <jim.baker at rackspace.com>
date:        Wed Jan 06 18:40:06 2016 -0700
summary:
  Convert iterators to both Object[] and primitive variants. Fixes #2279

files:
  Lib/test/test_array_jy.py                   |  10 +
  src/org/python/core/PyArray.java            |  66 +++++----
  src/org/python/core/PyIterator.java         |   4 +
  src/org/python/core/PyXRange.java           |   4 +
  src/org/python/core/ReflectedArgs.java      |  14 +-
  tests/java/org/python/core/PyArrayTest.java |  12 +
  6 files changed, 81 insertions(+), 29 deletions(-)


diff --git a/Lib/test/test_array_jy.py b/Lib/test/test_array_jy.py
--- a/Lib/test/test_array_jy.py
+++ b/Lib/test/test_array_jy.py
@@ -129,6 +129,16 @@
         self.assertAsList(jarray.array([1, 2, 3, 4, 5], "i"), [1, 2, 3, 4, 5])
         self.assertAsList(array("i", [1, 2, 3, 4, 5]), [1, 2, 3, 4, 5])
 
+    def test_auxillary_boxing(self):
+        "PyArray is internally used to support boxing of iterators/iterables"
+        self.assertAsList(xrange(5), [0, 1, 2, 3, 4])
+        self.assertAsList(iter(xrange(5)), [0, 1, 2, 3, 4])
+        self.assertAsList(list(xrange(5)), [0, 1, 2, 3, 4])
+        self.assertAsList((i * 2 for i in xrange(5)), [0, 2, 4, 6, 8])
+        self.assertAsList(iter((i * 2 for i in xrange(5))), [0, 2, 4, 6, 8])
+        self.assertAsList(iter((i * 2 for i in xrange(5))), [0, 2, 4, 6, 8])
+        self.assertAsList(itertools.chain('ABC', 'DEF'), ['A', 'B', 'C', 'D', 'E', 'F'])
+
     def test_object_varargs(self):
         "array.array objects can be used in the varargs position, with primitive boxing"
         a = array('i', range(5, 10))
diff --git a/src/org/python/core/PyArray.java b/src/org/python/core/PyArray.java
--- a/src/org/python/core/PyArray.java
+++ b/src/org/python/core/PyArray.java
@@ -57,6 +57,15 @@
         setup(type, data);
     }
 
+    public PyArray(Class<?> type, PyObject initial) {
+        this(TYPE);
+        this.type = type;
+        typecode = class2char(type);
+        data = Array.newInstance(type, 0);
+        delegate = new ArrayDelegate();
+        useInitial(initial);
+    }
+
     public PyArray(Class<?> type, int n) {
         this(type, Array.newInstance(type, n));
     }
@@ -77,6 +86,34 @@
         delegate = new ArrayDelegate();
     }
 
+    private void useInitial(PyObject initial) {
+        /*
+         * The initialiser may be omitted, or may validly be one of several types in the broad
+         * categories of a byte string (which is treated as a machine representation of the data) or
+         * an iterable yielding values assignable to the elements. There is special treatment for
+         * type 'u' Unicode.
+         */
+        if (initial == null) {
+            // Fall through
+
+        } else if (initial instanceof PyList) {
+            fromlist(initial);
+
+        } else if (initial instanceof PyString && !(initial instanceof PyUnicode)) {
+            fromstring(initial.toString());
+
+        } else if ("u".equals(typecode)) {
+            if (initial instanceof PyUnicode) {
+                extendArray(((PyUnicode)initial).toCodePoints());
+            } else {
+                extendUnicodeIter(initial);
+            }
+
+        } else {
+            extendInternal(initial);
+        }
+    }
+
     @ExposedNew
     static final PyObject array_new(PyNewWrapper new_, boolean init, PyType subtype,
             PyObject[] args, String[] keywords) {
@@ -130,34 +167,7 @@
         class2char(type);
         self.setup(type, Array.newInstance(type, 0));
         self.typecode = typecode;
-
-        /*
-         * The initialiser may be omitted, or may validly be one of several types in the broad
-         * categories of a byte string (which is treated as a machine representation of the data) or
-         * an iterable yielding values assignable to the elements. There is special treatment for
-         * type 'u' Unicode.
-         */
-        PyObject initial = ap.getPyObject(1, null);
-        if (initial == null) {
-            // Fall through
-
-        } else if (initial instanceof PyList) {
-            self.fromlist(initial);
-
-        } else if (initial instanceof PyString && !(initial instanceof PyUnicode)) {
-            self.fromstring(initial.toString());
-
-        } else if ("u".equals(typecode)) {
-            if (initial instanceof PyUnicode) {
-                self.extendArray(((PyUnicode)initial).toCodePoints());
-            } else {
-                self.extendUnicodeIter(initial);
-            }
-
-        } else {
-            self.extendInternal(initial);
-        }
-
+        self.useInitial(ap.getPyObject(1, null));
         return self;
     }
 
diff --git a/src/org/python/core/PyIterator.java b/src/org/python/core/PyIterator.java
--- a/src/org/python/core/PyIterator.java
+++ b/src/org/python/core/PyIterator.java
@@ -81,6 +81,10 @@
             }
             return list;
         }
+        if (c.isArray()) {
+            PyArray array = new PyArray(c.getComponentType(), this);
+            return array.__tojava__(c);
+        }
         return super.__tojava__(c);
     }
 
diff --git a/src/org/python/core/PyXRange.java b/src/org/python/core/PyXRange.java
--- a/src/org/python/core/PyXRange.java
+++ b/src/org/python/core/PyXRange.java
@@ -210,6 +210,10 @@
             }
             return list;
         }
+        if (c.isArray()) {
+            PyArray array = new PyArray(c.getComponentType(), this);
+            return array.__tojava__(c);
+        }
         return super.__tojava__(c);
     }
 }
diff --git a/src/org/python/core/ReflectedArgs.java b/src/org/python/core/ReflectedArgs.java
--- a/src/org/python/core/ReflectedArgs.java
+++ b/src/org/python/core/ReflectedArgs.java
@@ -155,7 +155,19 @@
             return pyArgs;
         }
         PyObject lastArg = pyArgs[pyArgs.length - 1];
-        if (lastArg instanceof PySequenceList || lastArg instanceof PyArray) {
+        if (lastArg instanceof PySequenceList ||
+                lastArg instanceof PyArray ||
+                lastArg instanceof PyXRange ||
+                lastArg instanceof PyIterator) {
+            // NOTE that the check is against PySequenceList, not PySequence,
+            // because certain Java <=> Python semantics currently require this
+            // additional strictness. Perhaps this can be relaxed.
+
+            // Empirically this list is exhaustive against the Jython runtime,
+            // excluding only PyBaseString, PyMemoryView, Py2kBuffer, BaseBytes,
+            // and AstList, many/most of which seem likely to be problematic for
+            // varargs usage.
+
             // FIXME also check if lastArg is sequence-like
             return pyArgs; // will be boxed in an array once __tojava__ is called
         }
diff --git a/tests/java/org/python/core/PyArrayTest.java b/tests/java/org/python/core/PyArrayTest.java
--- a/tests/java/org/python/core/PyArrayTest.java
+++ b/tests/java/org/python/core/PyArrayTest.java
@@ -1,6 +1,7 @@
 package org.python.core;
 
 import junit.framework.TestCase;
+import org.junit.Assert;
 import org.python.util.PythonInterpreter;
 
 /**
@@ -63,4 +64,15 @@
         assertEquals(0.0, a[0]);
         assertEquals(3.0, a[3]);
     }
+
+    public void testToJava() {
+        PythonInterpreter interp = new PythonInterpreter();
+        PyObject pyobj = interp.eval("[i * 2 for i in xrange(5)]");
+        Assert.assertArrayEquals
+                (new int[] {0, 2, 4, 6, 8},
+                (int[])pyobj.__tojava__(int[].class));
+        Assert.assertArrayEquals(
+                new Integer[] { 0, 2, 4, 6, 8},
+                (Object[])pyobj.__tojava__(Object[].class));
+    }
 }

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


More information about the Jython-checkins mailing list