|
From: <zy...@us...> - 2010-09-08 20:36:22
|
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.
|