Repository navigation
Regression in PyArray.pyset() for Boolean output setter #411
Description
Jython 2.7.4 breaks old (proper) behavior exhibited by 2.5.2 and below for java receiver type expecting boolean[] array causing regression.
Jython 2.7.4 impl: (broken)
jython/src/org/python/core/PyArray.java
Lines 2213 to 2220 in 3f256f4
| BOOLEAN("z", "boolean", Boolean.TYPE, 1, 0) { | |
| @Override | |
| void set(PyArray a, int i, PyObject value) { | |
| Array.setBoolean(a.data, i, value.__nonzero__()); | |
| } | |
Jython 2.5.2 impl: (works)
jython/src/org/python/core/PyArray.java
Lines 1470 to 1477 in 85c0618
| } | |
| } | |
| Object o = Py.tojava(value, type); | |
| if(o == Py.NoConversion) { | |
| throw Py.TypeError("Type not compatible with array type"); | |
| } | |
| Array.set(data, i, o); | |
| } |
In jython 2.5.2, for boolean array java receiver type, ex: someFunc(boolean[] array), the input value whatever it was ie primitive-java/object-java/python type was being converted to java type using Py.tojava(value, type).
But in jython 2.7.4, for the same receiver type, the input value matters if it is java-primitive/java-object/python type since not all of the java-Object types implement nonzero() and PyBoolean type is for python boolean values, currently the incoming java-object values all default to PyObject base impl for __nonzero() which just returns true always.
jython/src/org/python/core/PyObject.java
Lines 316 to 318 in 3f256f4
| public boolean __nonzero__() { | |
| return true; | |
| } |
This causes the inputs to the java-receiver function be all true, irrespective of what input was supplied from python script.
ex:
public class UnitUnderTest{
public void someFunc(boolean[] array){
if (array == null) {
System.out.println("null");
return;
}
System.out.print("[");
for (int i = 0; i < array.length; i++) {
System.out.print(array[I]);
if (i < (array.length-1)){
System.out.print(", ");
}
}
System.out.print("]");
}
}import java.lang.Boolean as Boolean
import java.lang.Boolean as Integer
a = [Boolean(0), Boolean(1), Boolean(0)] # java-object [<java.lang.Boolean>, <java.lang.Boolean>, <java.lang.Boolean>]
b = [0, 1, 0] # python [<integer>, <integer>, <integer>]
c = [Integer(0), Integer(1), Integer(0)] # java-object [<java.lang.Integer>, <java.lang.Integer>, <java.lang.Integer>]
# d = [boolean(0)] # INVALID - because python doesnt have a boolean keyword and cannot be imported as object unlike java.lang.Boolean.
import UnitUnderTest as uut
uut.someFunc(a) # prints all values as true ?!
uut.someFunc(b) # prints properly due to int values being python type (PyInteger) and all python types implement non-zero()
uut.someFunc(c) # prints all values as true ?! ######## jython 2.5.2 output #######
[false, true, false] # WORKS
[false, true, false] # WORKS
ERROR: Arg Integer can't be coerced into boolean. # WORKS! by throwing error######## jython 2.7.4 output #######
[true, true, true] # FAIL!
[false, true, false] # WORKS
[true, true, true] # FAIL!
Activity
mahee96 commentedon Jan 9, 2026
I can't seem to find the rationale behind the change to
Array.setBoolean(a.data, i, value.__nonzero__());instead ofArray.set(data, i, Py.tojava(value, type));but I can see this change came from 6756054
Can jython team shed some light on this refactor and the issue, Thanks in advance.
jeff5 commentedon Jan 10, 2026
Thanks for this well-researched issue. A couple of typos in your example, I think:
and
The rationale for the change overall is in the issue #119 linked in the commit, but whether
value.__nonzero__()was a better choice thanPy.tojava(value, type)can be questioned. In the original, there is no explicit handling of the boolean case, which seems to have been a later (non-CPython) addition.I remember finding the structure of this a bit muddled, so there was a lot to rationalise. But I did, and it will have passed tests.
I can reproduce what I think is this issue at the Jython prompt:
All good, but:
That's a surprise. I think you're right to trace it back to
__nonzero__, though, and it affects coercion generally, not just inPyArray. This is deeply suspicious:So it may be more a problem with coercion during calls or assignment. That has been a tricky area, and of course tests we took from CPython do not cover it, so it depends on our own thoroughness (in the distant past).
mahee96 commentedon Jan 10, 2026
thanks @jeff5 for the quick response and clarification on decision made during the refactor, appreciate it!.
Apologies for that typo in the example, and yeah you are right, I just typed into the editor directly, without validating the sample code as I was AFK.
no problem at all, but now that we acknowledge this needs to be revisited, is there any plans for a solution ? or at least as a containment fix, can we restore the behavior to Py.tojava().
As far as our diagnosis went, the issue was limited to Boolean since other setters in converter ItemType enum like USHORT, BYTE, INT etc were retaining original behavior.
What I was worried about in particular was that, reverting to old behavior would break something else in some other components as you pointed out (type coercion in general). Can you provide your inputs on this.
Also once this is fixed, maybe a test for this specific case could be added into:
PyArrayTest.javajython/tests/java/org/python/core/PyArrayTest.java
Line 10 in 3760bfb
jeff5 commentedon Jan 10, 2026
We tend to use a Python test if we can for the variant features. https://github.com/jython/jython/blob/master/Lib/test/test_array_jy.py