SF.net SVN: jython:[7115] trunk/jython

[email protected] Wed, 08 Sep 2010 20:36:16 +0000
Newsgroups gmane.comp.lang.jython.cvs
Message-ID <[email protected]>
Revision: 7115
          http://jython.svn.sourceforge.net/jython/?rev=7115&view=rev
Author:   zyasoft
Date:     2010-09-08 20:36:15 +0000 (Wed, 08 Sep 2010)

Log Message:
-----------
Fixed PyJavaType#setSlice so it properly works with Python objects
that are subclasses of Java classes implementing List. Resolves
#1397. Thanks Geoffrey French for the patch!

Modified Paths:
--------------
    trunk/jython/Lib/test/test_java_list_delegate.py
    trunk/jython/NEWS
    trunk/jython/src/org/python/core/PyJavaType.java
    trunk/jython/src/org/python/core/PyList.java

Modified: trunk/jython/Lib/test/test_java_list_delegate.py
===================================================================
--- trunk/jython/Lib/test/test_java_list_delegate.py	2010-09-08 11:37:00 UTC (rev 7114)
+++ trunk/jython/Lib/test/test_java_list_delegate.py	2010-09-08 20:36:15 UTC (rev 7115)
@@ -21,17 +21,25 @@
         except Exception, e:
             return type(e)
 
-    def check_list(self, control, results, initial):
-        for result in results:
+    def _arraylist_of(self, xs):
+        """
+        Converts a python list to a java.util.ArrayList
+        """
+        a = ArrayList()
+        a.addAll( xs )
+        return a
+
+    def check_list(self, control, results, list_type_names, initial, test_name):
+        for result, type_name in zip(results, list_type_names):
             try:
                 len(result)
             except:
                 print result
-            self.assertEquals(len(control), len(result), "%s is wrong for %s" % (type(result), initial))
-            for pvalue, jvalue in zip(control, result):
-                self.assertEquals(pvalue, jvalue)
+            self.assertEquals(len(control), len(result), "%s: length for %s does not match that of list" % (test_name, type_name))
+            for control_value, result_value in zip(control, result):
+                self.assertEquals(control_value, result_value, "%s: values from %s do not match those from list" % (test_name, type_name))
 
-    def _list_op_test(self, initial_value, op_func, check_value):
+    def _list_op_test(self, initial_value, op_func, test_name):
         """
         Tests a list operation
 
@@ -39,24 +47,33 @@
             - a python list
             - a java.util.List instance
 
-        givens the same result in both cases
+        gives the same result in both cases
         """
         lists = [list(initial_value), ArrayList(initial_value), Vector(initial_value)]
+        list_type_names = ['list', 'ArrayList', 'Vector']
 
         results = [self._perform_op(l, op_func) for l in lists]
-        self.check_list(lists[0], lists[1:], initial_value)
-        if check_value or not isinstance(results[0], list):
-            for r in results[1:]:
-                self.assertEquals(results[0], r)
+        self.check_list(lists[0], lists[1:], list_type_names[1:], initial_value, test_name)
+        if not isinstance(results[0], list):
+            for r,n in zip(results[1:], list_type_names[1:]):
+                self.assertEquals(results[0], r, '%s: result for list does not match result for java type %s' % (test_name,n) )
         else:
-            self.check_list(results[0], results[1:], initial_value)
+            self.check_list(results[0], results[1:], list_type_names[1:], initial_value, test_name)
 
     def test_get_integer(self):
         initial_value = range(0, 5)
 
         for i in xrange(-7, 7):
-            self._list_op_test(initial_value, lambda xs: xs[i], True)
+            self._list_op_test(initial_value, lambda xs: xs[i], 'get_integer [%d]' % (i,))
 
+    def test_get_slice(self):
+        initial_value = range(0, 5)
+        
+        for i in [None] + range(-7, 7):
+            for j in [None] + range(-7, 7):
+                for k in [None] + range(-7, 7):
+                    self._list_op_test(initial_value, lambda xs: xs[i:j:k], 'get_slice [%s:%s:%s]' % (i,j,k))
+
     def test_set_integer(self):
         initial_value = range(0, 5)
 
@@ -66,24 +83,27 @@
             return _f
 
         for i in xrange(-7, 7):
-            self._list_op_test(initial_value, make_op_func(i), True)
+            self._list_op_test(initial_value, make_op_func(i), 'set_integer [%d]' % (i,))
 
     def test_set_slice(self):
-        initial_value = range(0, 10)
+        initial_value = range(0, 5)
 
         def make_op_func(i, j, k, v):
             def _f(xs):
                 xs[i:j:k] = v
             return _f
+        
+        for i in [None] + range(-7, 7):
+            for j in [None] + range(-7, 7):
+                for k in [None] + range(-7, 7):
+                    self._list_op_test(initial_value, make_op_func(i, j, k, []), 'set_slice [%s:%s:%s]=[]' % (i,j,k))
+                    self._list_op_test(initial_value, make_op_func(i, j, k, range(0,2)), 'set_slice [%s:%s:%s]=range(0,2)' % (i,j,k))
+                    self._list_op_test(initial_value, make_op_func(i, j, k, range(0,4)), 'set_slice [%s:%s:%s]=range(0,4)' % (i,j,k))
+                    self._list_op_test(initial_value, make_op_func(i, j, k, xrange(0,2)), 'set_slice [%s:%s:%s]=xrange(0,2)' % (i,j,k))
+                    self._list_op_test(initial_value, make_op_func(i, j, k, self._arraylist_of(range(0,2))), 'set_slice [%s:%s:%s]=ArrayList(range(0,2))' % (i,j,k))
+ 
+        self._list_op_test([1,2,3,4,5], make_op_func(1, None, None, [1,2,3,4,5]), 'set_slice [1:]=[1,2,3,4,5]')
 
-        for i in xrange(-12, 12):
-            for j in xrange(-12, 12):
-                for k in xrange(-12, 12):
-                    self._list_op_test(initial_value, make_op_func(i, j, k, []), True)
-                    self._list_op_test(initial_value, make_op_func(i, j, k, range(0,2)), True)
-                    self._list_op_test(initial_value, make_op_func(i, j, k, range(0,4)), True)
-                    self._list_op_test(initial_value, make_op_func(i, j, k, xrange(0,2)), True)
-
     def test_del_integer(self):
         initial_value = range(0,5)
 
@@ -93,20 +113,20 @@
             return _f
 
         for i in xrange(-7, 7):
-            self._list_op_test(initial_value, make_op_func(i), True)
+            self._list_op_test(initial_value, make_op_func(i), 'del_integer [%d]' % (i,))
 
     def test_del_slice(self):
-        initial_value = range(0,10)
+        initial_value = range(0,5)
 
         def make_op_func(i, j, k):
             def _f(xs):
                 del xs[i:j:k]
             return _f
 
-        for i in xrange(-12, 12):
-            for j in xrange(-12, 12):
-                for k in xrange(-12, 12):
-                    self._list_op_test(initial_value, make_op_func(i, j, k), True)
+        for i in [None] + range(-7, 7):
+            for j in [None] + range(-7, 7):
+                for k in [None] + range(-7, 7):
+                    self._list_op_test(initial_value, make_op_func(i, j, k), 'del_slice [%s:%s:%s]' % (i,j,k))
 
     def test_len(self):
         jlist = ArrayList()
@@ -174,6 +194,43 @@
         self.assert_(m.size() == 11)
         self.assert_(m.get(10) == 84)
 
+        
+        
+    def test_set_slice_from_input_types(self):
+        """
+        Tests the slice setting functionality of Python lists
+        Ensures that the results are all the same, whether the source list is a Python list, a java.util.List or an iterator
+        """
+        initial_value = range(0, 5)
+        
+        def make_op_func(i, j, k, v):
+            def _f(xs):
+                xs[i:j:k] = v
+            return _f
+        
+        for i in [None] + range(-7, 7):
+            for j in [None] + range(-7, 7):
+                for k in [None] + range(-7, 7):
+                    destPy = copy(initial_value)
+                    destJUL = copy(initial_value)
+                    destIter = copy(initial_value)
+                    
+                    sourcePy = range(0, 2)
+                    sourceJUL = self._arraylist_of(range(0, 2))
+                    sourceIter = xrange(0, 2)
+                    
+                    resultPy = self._perform_op(destPy, make_op_func(i, j, k, sourcePy))
+                    resultJUL = self._perform_op(destJUL, make_op_func(i, j, k, sourceJUL))
+                    resultIter = self._perform_op(destIter, make_op_func(i, j, k, sourceIter))
+                    
+                    self.assertEquals(resultPy, resultJUL)
+                    self.assertEquals(resultPy, resultIter)
+
+                    self.assertEquals(destPy, destJUL)
+                    self.assertEquals(destPy, destIter)
+
+
+
 def test_main():
     test.test_support.run_unittest(CollectionProxyTest)
 

Modified: trunk/jython/NEWS
===================================================================
--- trunk/jython/NEWS	2010-09-08 11:37:00 UTC (rev 7114)
+++ trunk/jython/NEWS	2010-09-08 20:36:15 UTC (rev 7115)
@@ -2,6 +2,7 @@
 
 Jython 2.5.2b2
   Bugs Fixed
+    - [ 1397 ] Bugs in PyList and PyJavaType.ListIndexDelegate slice setting
     - [ 1503 ] Java constructors should take keyword arguments
     - [ 1648 ] Incomplete implementation of pep328 for relative imports
     - [ 1611 ] Jython bytecode violated JLS, causing NPE on Sun's JVM when using -Xcomp option

Modified: trunk/jython/src/org/python/core/PyJavaType.java
===================================================================
--- trunk/jython/src/org/python/core/PyJavaType.java	2010-09-08 11:37:00 UTC (rev 7114)
+++ trunk/jython/src/org/python/core/PyJavaType.java	2010-09-08 20:36:15 UTC (rev 7115)
@@ -1079,26 +1079,94 @@
         public void setItem(int idx, PyObject value) {
             list.set(idx, value.__tojava__(Object.class));
         }
-
+        
         @Override
         public void setSlice(int start, int stop, int step, PyObject value) {
-            if (step == 0) {
-                return;
+            if (stop < start) {
+                stop = start;
             }
-            if (value.javaProxy == this) {
-                List newseq = new ArrayList(len());
-                for (Object object : ((List)value.javaProxy)) {
-                    newseq.add(object);
+            if (value.javaProxy == this.list) {
+                List<Object> xs = Generic.list();
+                xs.addAll(this.list);
+                setsliceList(start, stop, step, xs);
+            } else if (value instanceof PyList) {
+                setslicePyList(start, stop, step, (PyList)value);
+            } else {
+                Object valueList = value.__tojava__(List.class);
+                if (valueList != null && valueList != Py.NoConversion) {
+                    setsliceList(start, stop, step, (List)valueList);
+                } else {
+                    setsliceIterator(start, stop, step, value.asIterable().iterator());
                 }
-                value = Py.java2py(newseq);
             }
-            int j = start;
-            for (PyObject obj : value.asIterable()) {
-                setItem(j, obj);
-                j += step;
+        }
+
+        
+        
+        final private void setsliceList(int start, int stop, int step, List<Object> value) {
+            if (step == 1) {
+                list.subList(start, stop).clear();
+                list.addAll(start, value);
+            } else {
+                int size = list.size();
+                Iterator<Object> iter = value.listIterator();
+                for (int j = start; iter.hasNext(); j += step) {
+                    Object item =iter.next();
+                    if (j >= size) {
+                        list.add(item);
+                    } else {
+                        list.set(j, item);
+                    }
+                }
             }
         }
 
+        final private void setsliceIterator(int start, int stop, int step, Iterator<PyObject> iter) {
+            if (step == 1) {
+                List<Object> insertion = new ArrayList<Object>();
+                if (iter != null) {
+                    while (iter.hasNext()) {
+                        insertion.add(iter.next().__tojava__(Object.class));
+                    }
+                }
+                list.subList(start, stop).clear();
+                list.addAll(start, insertion);
+            } else {
+                int size = list.size();
+                for (int j = start; iter.hasNext(); j += step) {
+                    Object item = iter.next().__tojava__(Object.class);
+                    if (j >= size) {
+                        list.add(item);
+                    } else {
+                        list.set(j, item);
+                    }
+                }
+            }
+        }
+
+        final private void setslicePyList(int start, int stop, int step, PyList value) {
+            if (step == 1) {
+                list.subList(start, stop).clear();
+                int n = value.getList().size();
+                for (int i=0, j=start; i<n; i++, j++) {
+                    Object item = value.getList().get(i).__tojava__(Object.class);
+                    list.add(j, item);
+                }
+            } else {
+                int size = list.size();
+                Iterator<PyObject> iter = value.getList().listIterator();
+                for (int j = start; iter.hasNext(); j += step) {
+                    Object item = iter.next().__tojava__(Object.class);
+                    if (j >= size) {
+                        list.add(item);
+                    } else {
+                        list.set(j, item);
+                    }
+                }
+            }
+        }
+
+        
         @Override
         public void delItems(int start, int stop) {
             int n = stop - start;

Modified: trunk/jython/src/org/python/core/PyList.java
===================================================================
--- trunk/jython/src/org/python/core/PyList.java	2010-09-08 11:37:00 UTC (rev 7114)
+++ trunk/jython/src/org/python/core/PyList.java	2010-09-08 20:36:15 UTC (rev 7115)
@@ -147,26 +147,38 @@
             setslicePyList(start, stop, step, (PyList) value);
         } else if (value instanceof PySequence) {
             setsliceIterator(start, stop, step, value.asIterable().iterator());
-        } else if (value != null && !(value instanceof List)) {
-            value = new PyList(value);
-            setsliceIterator(start, stop, step, value.asIterable().iterator());
+        } else if (value instanceof List) {
+                setsliceList(start, stop, step, (List)value);
         } else {
-            List valueList = (List) value.__tojava__(List.class);
+            Object valueList = value.__tojava__(List.class);
             if (valueList != null && valueList != Py.NoConversion) {
-                setsliceList(start, stop, step, valueList);
+                setsliceList(start, stop, step, (List)valueList);
+            } else {
+                value = new PyList(value);
+                setsliceIterator(start, stop, step, value.asIterable().iterator());
             }
         }
     }
 
     final private void setsliceList(int start, int stop, int step, List value) {
-        int n = sliceLength(start, stop, step);
-        if (list instanceof ArrayList) {
-            ((ArrayList) list).ensureCapacity(start + n);
+        if (step == 1) {
+            list.subList(start, stop).clear();
+            int n = value.size();
+            for (int i=0, j=start; i<n; i++, j++) {
+                list.add(j, Py.java2py(value.get(i)));
+            }
+        } else {
+            int size = list.size();
+            Iterator<Object> iter = value.listIterator();
+            for (int j = start; iter.hasNext(); j += step) {
+                PyObject item = Py.java2py(iter.next());
+                if (j >= size) {
+                    list.add(item);
+                } else {
+                    list.set(j, item);
+                }
+            }
         }
-        ListIterator src = value.listIterator();
-        for (int j = start; src.hasNext(); j += step) {
-            set(j, src.next());
-        }
     }
 
     final private void setsliceIterator(int start, int stop, int step, Iterator<PyObject> iter) {


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.

------------------------------------------------------------------------------
This SF.net Dev2Dev email is sponsored by:

Show off your parallel programming skills.
Enter the Intel(R) Threading Challenge 2010.
http://p.sf.net/sfu/intel-thread-sfd