← 输入框|github.com|刷新
Skip to content

Regression in PyArray.pyset() for Boolean output setter #411

Open

Description

@mahee96

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)

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)

}
}
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.

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

  1. mahee96 commented on Jan 9, 2026

    @mahee96
    Author

    I can't seem to find the rationale behind the change to Array.setBoolean(a.data, i, value.__nonzero__()); instead of Array.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.

  2. jeff5 commented on Jan 10, 2026

    @jeff5
    Member

    Thanks for this well-researched issue. A couple of typos in your example, I think:

    import java.lang.Boolean as Boolean
    import java.lang.Boolean as Integer   # ???
    

    and

    System.out.print(array[I]);  // ??? i ?
    

    The rationale for the change overall is in the issue #119 linked in the commit, but whether value.__nonzero__() was a better choice than Py.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:

    >>> from java.lang import Integer, Boolean
    >>> from array import array
    >>> Boolean(0), Boolean(1), Boolean(False), Boolean(True)
    (false, true, false, true)
    >>> array('z', [0,1])
    array('z', [False, True])
    >>> array('z', [False, True])
    array('z', [False, True])
    

    All good, but:

    >>> array('z', [Boolean(0), Boolean(1)])
    array('z', [True, True])
    

    That's a surprise. I think you're right to trace it back to __nonzero__, though, and it affects coercion generally, not just in PyArray. This is deeply suspicious:

    >>> bool(0)
    False
    >>> bool(Boolean(0))
    True
    >>> bool(Boolean(0)).__nonzero__()
    True
    >>> bool(0)
    False
    >>> array('z', [Integer(0), Integer(1)])
    array('z', [True, True])
    >>> bool(Integer(0))
    True
    

    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).

  3. mahee96 commented on Jan 10, 2026

    @mahee96
    Author

    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.

    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).

    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.java

    public class PyArrayTest extends TestCase {

  4. jeff5 commented on Jan 10, 2026

    @jeff5
    Member

    Also once this is fixed, maybe a test for this specific case could be added into: PyArrayTest.java

    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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions