Message10865

Author jsaiz
Recipients jsaiz
Date 2016-06-17.08:30:27
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1466152229.27.0.385085108097.issue2505@psf.upfronthosting.co.za>
In-reply-to
Content
Unpack the attached jar file.

It contains a Jython file, with a test class extending unittest.TestCase, and a simple Java class that I reproduce here for convenience:

import org.python.core.PySystemState;
import org.python.util.PythonInterpreter;

public class InterpreterTest {
    public static void main(String[] args) {
        findTestCases(new PythonInterpreter(null, new PySystemState()));
        findTestCases(new PythonInterpreter());
    }

    private static void findTestCases(PythonInterpreter interpreter) {
        interpreter.exec("import unittest");
        interpreter.exec("import module.sometest");
        System.out.println(interpreter.eval("unittest.findTestCases(module.sometest)"));
    }
}

The purpose of this Java class is to print the test cases found in the Jython file.

As the Jython class contains two test methods, the result of executing InterpreterTest should be that they are printed twice (one by each interpreter). However, the output of this program is:

linux> java InterpreterTest
<unittest.suite.TestSuite tests=[]>
<unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[<module.sometest.SomeTest testMethod=testOne>, <module.sometest.SomeTest testMethod=testTwo>]>]>

I've been debugging and the cause is not easy to explain, but in summary it is due to the PySystemState passed to the first interpreter being lost, because Py.getSystemState() accesses in the end ThreadStateMapping.cachedThreadState, which has weak references to the ThreadState objects. As the PySystemState is accessed through the ThreadState, if the ThreadState is garbage collected, then the default initial PySystemState is used.

This, in combination of the fact that PyType.isSubType uses the == operator for checking equality of PyType objects, rather than the equals method, produces that two different instances of PyType representing unittest.TestCase are found to be different, so the example SomeTest is not detected to extend unittest.TestCase in the first case.

A solution would be to somehow make hard references to the ThreadState objects.

We've solve this by holding a WeakHashMap<PythonInterpreter, ThreadState> that only frees the ThreadState when its interpreter is garbage collected, but other better solution could be found.
History
Date User Action Args
2016-06-17 08:30:29jsaizsetrecipients: + jsaiz
2016-06-17 08:30:29jsaizsetmessageid: <1466152229.27.0.385085108097.issue2505@psf.upfronthosting.co.za>
2016-06-17 08:30:29jsaizlinkissue2505 messages
2016-06-17 08:30:27jsaizcreate